libsmbclient: Use tevent_req_poll_ntstatus in cli_openx
[metze/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 = talloc_stackframe();
1101         struct tevent_context *ev;
1102         struct tevent_req *req;
1103         NTSTATUS status = NT_STATUS_OK;
1104
1105         if (smbXcli_conn_has_async_calls(cli->conn)) {
1106                 /*
1107                  * Can't use sync call while an async call is in flight
1108                  */
1109                 status = NT_STATUS_INVALID_PARAMETER;
1110                 goto fail;
1111         }
1112
1113         ev = samba_tevent_context_init(frame);
1114         if (ev == NULL) {
1115                 status = NT_STATUS_NO_MEMORY;
1116                 goto fail;
1117         }
1118
1119         req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
1120         if (req == NULL) {
1121                 status = NT_STATUS_NO_MEMORY;
1122                 goto fail;
1123         }
1124
1125         if (!tevent_req_poll(req, ev)) {
1126                 status = map_nt_error_from_unix(errno);
1127                 goto fail;
1128         }
1129
1130         status = cli_rename_recv(req);
1131
1132  fail:
1133         TALLOC_FREE(frame);
1134         return status;
1135 }
1136
1137 /****************************************************************************
1138  NT Rename a file.
1139 ****************************************************************************/
1140
1141 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1142
1143 struct cli_ntrename_internal_state {
1144         uint16_t vwv[4];
1145 };
1146
1147 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1148                                 struct tevent_context *ev,
1149                                 struct cli_state *cli,
1150                                 const char *fname_src,
1151                                 const char *fname_dst,
1152                                 uint16_t rename_flag)
1153 {
1154         struct tevent_req *req = NULL, *subreq = NULL;
1155         struct cli_ntrename_internal_state *state = NULL;
1156         uint8_t additional_flags = 0;
1157         uint8_t *bytes = NULL;
1158
1159         req = tevent_req_create(mem_ctx, &state,
1160                                 struct cli_ntrename_internal_state);
1161         if (req == NULL) {
1162                 return NULL;
1163         }
1164
1165         SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1166         SSVAL(state->vwv+1, 0, rename_flag);
1167
1168         bytes = talloc_array(state, uint8_t, 1);
1169         if (tevent_req_nomem(bytes, req)) {
1170                 return tevent_req_post(req, ev);
1171         }
1172         bytes[0] = 4;
1173         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_src,
1174                                    strlen(fname_src)+1, NULL);
1175         if (tevent_req_nomem(bytes, req)) {
1176                 return tevent_req_post(req, ev);
1177         }
1178
1179         bytes = talloc_realloc(state, bytes, uint8_t,
1180                         talloc_get_size(bytes)+1);
1181         if (tevent_req_nomem(bytes, req)) {
1182                 return tevent_req_post(req, ev);
1183         }
1184
1185         bytes[talloc_get_size(bytes)-1] = 4;
1186         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname_dst,
1187                                    strlen(fname_dst)+1, NULL);
1188         if (tevent_req_nomem(bytes, req)) {
1189                 return tevent_req_post(req, ev);
1190         }
1191
1192         subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1193                               4, state->vwv, talloc_get_size(bytes), bytes);
1194         if (tevent_req_nomem(subreq, req)) {
1195                 return tevent_req_post(req, ev);
1196         }
1197         tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1198         return req;
1199 }
1200
1201 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1202 {
1203         struct tevent_req *req = tevent_req_callback_data(
1204                                 subreq, struct tevent_req);
1205         NTSTATUS status;
1206
1207         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1208         TALLOC_FREE(subreq);
1209         if (tevent_req_nterror(req, status)) {
1210                 return;
1211         }
1212         tevent_req_done(req);
1213 }
1214
1215 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1216 {
1217         return tevent_req_simple_recv_ntstatus(req);
1218 }
1219
1220 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1221                                 struct tevent_context *ev,
1222                                 struct cli_state *cli,
1223                                 const char *fname_src,
1224                                 const char *fname_dst)
1225 {
1226         return cli_ntrename_internal_send(mem_ctx,
1227                                           ev,
1228                                           cli,
1229                                           fname_src,
1230                                           fname_dst,
1231                                           RENAME_FLAG_RENAME);
1232 }
1233
1234 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1235 {
1236         return cli_ntrename_internal_recv(req);
1237 }
1238
1239 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1240 {
1241         TALLOC_CTX *frame = talloc_stackframe();
1242         struct tevent_context *ev;
1243         struct tevent_req *req;
1244         NTSTATUS status = NT_STATUS_OK;
1245
1246         if (smbXcli_conn_has_async_calls(cli->conn)) {
1247                 /*
1248                  * Can't use sync call while an async call is in flight
1249                  */
1250                 status = NT_STATUS_INVALID_PARAMETER;
1251                 goto fail;
1252         }
1253
1254         ev = samba_tevent_context_init(frame);
1255         if (ev == NULL) {
1256                 status = NT_STATUS_NO_MEMORY;
1257                 goto fail;
1258         }
1259
1260         req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1261         if (req == NULL) {
1262                 status = NT_STATUS_NO_MEMORY;
1263                 goto fail;
1264         }
1265
1266         if (!tevent_req_poll(req, ev)) {
1267                 status = map_nt_error_from_unix(errno);
1268                 goto fail;
1269         }
1270
1271         status = cli_ntrename_recv(req);
1272
1273  fail:
1274         TALLOC_FREE(frame);
1275         return status;
1276 }
1277
1278 /****************************************************************************
1279  NT hardlink a file.
1280 ****************************************************************************/
1281
1282 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1283                                 struct tevent_context *ev,
1284                                 struct cli_state *cli,
1285                                 const char *fname_src,
1286                                 const char *fname_dst)
1287 {
1288         return cli_ntrename_internal_send(mem_ctx,
1289                                           ev,
1290                                           cli,
1291                                           fname_src,
1292                                           fname_dst,
1293                                           RENAME_FLAG_HARD_LINK);
1294 }
1295
1296 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1297 {
1298         return cli_ntrename_internal_recv(req);
1299 }
1300
1301 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1302 {
1303         TALLOC_CTX *frame = talloc_stackframe();
1304         struct tevent_context *ev;
1305         struct tevent_req *req;
1306         NTSTATUS status = NT_STATUS_OK;
1307
1308         if (smbXcli_conn_has_async_calls(cli->conn)) {
1309                 /*
1310                  * Can't use sync call while an async call is in flight
1311                  */
1312                 status = NT_STATUS_INVALID_PARAMETER;
1313                 goto fail;
1314         }
1315
1316         ev = samba_tevent_context_init(frame);
1317         if (ev == NULL) {
1318                 status = NT_STATUS_NO_MEMORY;
1319                 goto fail;
1320         }
1321
1322         req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1323         if (req == NULL) {
1324                 status = NT_STATUS_NO_MEMORY;
1325                 goto fail;
1326         }
1327
1328         if (!tevent_req_poll(req, ev)) {
1329                 status = map_nt_error_from_unix(errno);
1330                 goto fail;
1331         }
1332
1333         status = cli_nt_hardlink_recv(req);
1334
1335  fail:
1336         TALLOC_FREE(frame);
1337         return status;
1338 }
1339
1340 /****************************************************************************
1341  Delete a file.
1342 ****************************************************************************/
1343
1344 static void cli_unlink_done(struct tevent_req *subreq);
1345
1346 struct cli_unlink_state {
1347         uint16_t vwv[1];
1348 };
1349
1350 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1351                                 struct tevent_context *ev,
1352                                 struct cli_state *cli,
1353                                 const char *fname,
1354                                 uint16_t mayhave_attrs)
1355 {
1356         struct tevent_req *req = NULL, *subreq = NULL;
1357         struct cli_unlink_state *state = NULL;
1358         uint8_t additional_flags = 0;
1359         uint8_t *bytes = NULL;
1360
1361         req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1362         if (req == NULL) {
1363                 return NULL;
1364         }
1365
1366         SSVAL(state->vwv+0, 0, mayhave_attrs);
1367
1368         bytes = talloc_array(state, uint8_t, 1);
1369         if (tevent_req_nomem(bytes, req)) {
1370                 return tevent_req_post(req, ev);
1371         }
1372         bytes[0] = 4;
1373         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
1374                                    strlen(fname)+1, NULL);
1375
1376         if (tevent_req_nomem(bytes, req)) {
1377                 return tevent_req_post(req, ev);
1378         }
1379
1380         subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1381                                 1, state->vwv, talloc_get_size(bytes), bytes);
1382         if (tevent_req_nomem(subreq, req)) {
1383                 return tevent_req_post(req, ev);
1384         }
1385         tevent_req_set_callback(subreq, cli_unlink_done, req);
1386         return req;
1387 }
1388
1389 static void cli_unlink_done(struct tevent_req *subreq)
1390 {
1391         struct tevent_req *req = tevent_req_callback_data(
1392                 subreq, struct tevent_req);
1393         NTSTATUS status;
1394
1395         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1396         TALLOC_FREE(subreq);
1397         if (tevent_req_nterror(req, status)) {
1398                 return;
1399         }
1400         tevent_req_done(req);
1401 }
1402
1403 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1404 {
1405         return tevent_req_simple_recv_ntstatus(req);
1406 }
1407
1408 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1409 {
1410         TALLOC_CTX *frame = talloc_stackframe();
1411         struct tevent_context *ev;
1412         struct tevent_req *req;
1413         NTSTATUS status = NT_STATUS_OK;
1414
1415         if (smbXcli_conn_has_async_calls(cli->conn)) {
1416                 /*
1417                  * Can't use sync call while an async call is in flight
1418                  */
1419                 status = NT_STATUS_INVALID_PARAMETER;
1420                 goto fail;
1421         }
1422
1423         ev = samba_tevent_context_init(frame);
1424         if (ev == NULL) {
1425                 status = NT_STATUS_NO_MEMORY;
1426                 goto fail;
1427         }
1428
1429         req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1430         if (req == NULL) {
1431                 status = NT_STATUS_NO_MEMORY;
1432                 goto fail;
1433         }
1434
1435         if (!tevent_req_poll(req, ev)) {
1436                 status = map_nt_error_from_unix(errno);
1437                 goto fail;
1438         }
1439
1440         status = cli_unlink_recv(req);
1441
1442  fail:
1443         TALLOC_FREE(frame);
1444         return status;
1445 }
1446
1447 /****************************************************************************
1448  Create a directory.
1449 ****************************************************************************/
1450
1451 static void cli_mkdir_done(struct tevent_req *subreq);
1452
1453 struct cli_mkdir_state {
1454         int dummy;
1455 };
1456
1457 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1458                                   struct tevent_context *ev,
1459                                   struct cli_state *cli,
1460                                   const char *dname)
1461 {
1462         struct tevent_req *req = NULL, *subreq = NULL;
1463         struct cli_mkdir_state *state = NULL;
1464         uint8_t additional_flags = 0;
1465         uint8_t *bytes = NULL;
1466
1467         req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1468         if (req == NULL) {
1469                 return NULL;
1470         }
1471
1472         bytes = talloc_array(state, uint8_t, 1);
1473         if (tevent_req_nomem(bytes, req)) {
1474                 return tevent_req_post(req, ev);
1475         }
1476         bytes[0] = 4;
1477         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1478                                    strlen(dname)+1, NULL);
1479
1480         if (tevent_req_nomem(bytes, req)) {
1481                 return tevent_req_post(req, ev);
1482         }
1483
1484         subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1485                               0, NULL, talloc_get_size(bytes), bytes);
1486         if (tevent_req_nomem(subreq, req)) {
1487                 return tevent_req_post(req, ev);
1488         }
1489         tevent_req_set_callback(subreq, cli_mkdir_done, req);
1490         return req;
1491 }
1492
1493 static void cli_mkdir_done(struct tevent_req *subreq)
1494 {
1495         struct tevent_req *req = tevent_req_callback_data(
1496                 subreq, struct tevent_req);
1497         NTSTATUS status;
1498
1499         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1500         TALLOC_FREE(subreq);
1501         if (tevent_req_nterror(req, status)) {
1502                 return;
1503         }
1504         tevent_req_done(req);
1505 }
1506
1507 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1508 {
1509         return tevent_req_simple_recv_ntstatus(req);
1510 }
1511
1512 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1513 {
1514         TALLOC_CTX *frame = talloc_stackframe();
1515         struct tevent_context *ev;
1516         struct tevent_req *req;
1517         NTSTATUS status = NT_STATUS_OK;
1518
1519         if (smbXcli_conn_has_async_calls(cli->conn)) {
1520                 /*
1521                  * Can't use sync call while an async call is in flight
1522                  */
1523                 status = NT_STATUS_INVALID_PARAMETER;
1524                 goto fail;
1525         }
1526
1527         ev = samba_tevent_context_init(frame);
1528         if (ev == NULL) {
1529                 status = NT_STATUS_NO_MEMORY;
1530                 goto fail;
1531         }
1532
1533         req = cli_mkdir_send(frame, ev, cli, dname);
1534         if (req == NULL) {
1535                 status = NT_STATUS_NO_MEMORY;
1536                 goto fail;
1537         }
1538
1539         if (!tevent_req_poll(req, ev)) {
1540                 status = map_nt_error_from_unix(errno);
1541                 goto fail;
1542         }
1543
1544         status = cli_mkdir_recv(req);
1545
1546  fail:
1547         TALLOC_FREE(frame);
1548         return status;
1549 }
1550
1551 /****************************************************************************
1552  Remove a directory.
1553 ****************************************************************************/
1554
1555 static void cli_rmdir_done(struct tevent_req *subreq);
1556
1557 struct cli_rmdir_state {
1558         int dummy;
1559 };
1560
1561 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1562                                   struct tevent_context *ev,
1563                                   struct cli_state *cli,
1564                                   const char *dname)
1565 {
1566         struct tevent_req *req = NULL, *subreq = NULL;
1567         struct cli_rmdir_state *state = NULL;
1568         uint8_t additional_flags = 0;
1569         uint8_t *bytes = NULL;
1570
1571         req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1572         if (req == NULL) {
1573                 return NULL;
1574         }
1575
1576         bytes = talloc_array(state, uint8_t, 1);
1577         if (tevent_req_nomem(bytes, req)) {
1578                 return tevent_req_post(req, ev);
1579         }
1580         bytes[0] = 4;
1581         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), dname,
1582                                    strlen(dname)+1, NULL);
1583
1584         if (tevent_req_nomem(bytes, req)) {
1585                 return tevent_req_post(req, ev);
1586         }
1587
1588         subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1589                               0, NULL, talloc_get_size(bytes), bytes);
1590         if (tevent_req_nomem(subreq, req)) {
1591                 return tevent_req_post(req, ev);
1592         }
1593         tevent_req_set_callback(subreq, cli_rmdir_done, req);
1594         return req;
1595 }
1596
1597 static void cli_rmdir_done(struct tevent_req *subreq)
1598 {
1599         struct tevent_req *req = tevent_req_callback_data(
1600                 subreq, struct tevent_req);
1601         NTSTATUS status;
1602
1603         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1604         TALLOC_FREE(subreq);
1605         if (tevent_req_nterror(req, status)) {
1606                 return;
1607         }
1608         tevent_req_done(req);
1609 }
1610
1611 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1612 {
1613         return tevent_req_simple_recv_ntstatus(req);
1614 }
1615
1616 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1617 {
1618         TALLOC_CTX *frame = talloc_stackframe();
1619         struct tevent_context *ev;
1620         struct tevent_req *req;
1621         NTSTATUS status = NT_STATUS_OK;
1622
1623         if (smbXcli_conn_has_async_calls(cli->conn)) {
1624                 /*
1625                  * Can't use sync call while an async call is in flight
1626                  */
1627                 status = NT_STATUS_INVALID_PARAMETER;
1628                 goto fail;
1629         }
1630
1631         ev = samba_tevent_context_init(frame);
1632         if (ev == NULL) {
1633                 status = NT_STATUS_NO_MEMORY;
1634                 goto fail;
1635         }
1636
1637         req = cli_rmdir_send(frame, ev, cli, dname);
1638         if (req == NULL) {
1639                 status = NT_STATUS_NO_MEMORY;
1640                 goto fail;
1641         }
1642
1643         if (!tevent_req_poll(req, ev)) {
1644                 status = map_nt_error_from_unix(errno);
1645                 goto fail;
1646         }
1647
1648         status = cli_rmdir_recv(req);
1649
1650  fail:
1651         TALLOC_FREE(frame);
1652         return status;
1653 }
1654
1655 /****************************************************************************
1656  Set or clear the delete on close flag.
1657 ****************************************************************************/
1658
1659 struct doc_state {
1660         uint16_t setup;
1661         uint8_t param[6];
1662         uint8_t data[1];
1663 };
1664
1665 static void cli_nt_delete_on_close_done(struct tevent_req *subreq)
1666 {
1667         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
1668                                          NULL, 0, NULL, NULL, 0, NULL);
1669         tevent_req_simple_finish_ntstatus(subreq, status);
1670 }
1671
1672 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1673                                         struct tevent_context *ev,
1674                                         struct cli_state *cli,
1675                                         uint16_t fnum,
1676                                         bool flag)
1677 {
1678         struct tevent_req *req = NULL, *subreq = NULL;
1679         struct doc_state *state = NULL;
1680
1681         req = tevent_req_create(mem_ctx, &state, struct doc_state);
1682         if (req == NULL) {
1683                 return NULL;
1684         }
1685
1686         /* Setup setup word. */
1687         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1688
1689         /* Setup param array. */
1690         SSVAL(state->param,0,fnum);
1691         SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1692
1693         /* Setup data array. */
1694         SCVAL(&state->data[0], 0, flag ? 1 : 0);
1695
1696         subreq = cli_trans_send(state,                  /* mem ctx. */
1697                                 ev,                     /* event ctx. */
1698                                 cli,                    /* cli_state. */
1699                                 SMBtrans2,              /* cmd. */
1700                                 NULL,                   /* pipe name. */
1701                                 -1,                     /* fid. */
1702                                 0,                      /* function. */
1703                                 0,                      /* flags. */
1704                                 &state->setup,          /* setup. */
1705                                 1,                      /* num setup uint16_t words. */
1706                                 0,                      /* max returned setup. */
1707                                 state->param,           /* param. */
1708                                 6,                      /* num param. */
1709                                 2,                      /* max returned param. */
1710                                 state->data,            /* data. */
1711                                 1,                      /* num data. */
1712                                 0);                     /* max returned data. */
1713
1714         if (tevent_req_nomem(subreq, req)) {
1715                 return tevent_req_post(req, ev);
1716         }
1717         tevent_req_set_callback(subreq, cli_nt_delete_on_close_done, req);
1718         return req;
1719 }
1720
1721 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1722 {
1723         return tevent_req_simple_recv_ntstatus(req);
1724 }
1725
1726 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1727 {
1728         TALLOC_CTX *frame = talloc_stackframe();
1729         struct tevent_context *ev = NULL;
1730         struct tevent_req *req = NULL;
1731         NTSTATUS status = NT_STATUS_OK;
1732
1733         if (smbXcli_conn_has_async_calls(cli->conn)) {
1734                 /*
1735                  * Can't use sync call while an async call is in flight
1736                  */
1737                 status = NT_STATUS_INVALID_PARAMETER;
1738                 goto fail;
1739         }
1740
1741         ev = samba_tevent_context_init(frame);
1742         if (ev == NULL) {
1743                 status = NT_STATUS_NO_MEMORY;
1744                 goto fail;
1745         }
1746
1747         req = cli_nt_delete_on_close_send(frame,
1748                                 ev,
1749                                 cli,
1750                                 fnum,
1751                                 flag);
1752         if (req == NULL) {
1753                 status = NT_STATUS_NO_MEMORY;
1754                 goto fail;
1755         }
1756
1757         if (!tevent_req_poll(req, ev)) {
1758                 status = map_nt_error_from_unix(errno);
1759                 goto fail;
1760         }
1761
1762         status = cli_nt_delete_on_close_recv(req);
1763
1764  fail:
1765         TALLOC_FREE(frame);
1766         return status;
1767 }
1768
1769 struct cli_ntcreate_state {
1770         uint16_t vwv[24];
1771         uint16_t fnum;
1772 };
1773
1774 static void cli_ntcreate_done(struct tevent_req *subreq);
1775
1776 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
1777                                      struct tevent_context *ev,
1778                                      struct cli_state *cli,
1779                                      const char *fname,
1780                                      uint32_t CreatFlags,
1781                                      uint32_t DesiredAccess,
1782                                      uint32_t FileAttributes,
1783                                      uint32_t ShareAccess,
1784                                      uint32_t CreateDisposition,
1785                                      uint32_t CreateOptions,
1786                                      uint8_t SecurityFlags)
1787 {
1788         struct tevent_req *req, *subreq;
1789         struct cli_ntcreate_state *state;
1790         uint16_t *vwv;
1791         uint8_t *bytes;
1792         size_t converted_len;
1793
1794         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
1795         if (req == NULL) {
1796                 return NULL;
1797         }
1798
1799         vwv = state->vwv;
1800
1801         SCVAL(vwv+0, 0, 0xFF);
1802         SCVAL(vwv+0, 1, 0);
1803         SSVAL(vwv+1, 0, 0);
1804         SCVAL(vwv+2, 0, 0);
1805
1806         if (cli->use_oplocks) {
1807                 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1808         }
1809         SIVAL(vwv+3, 1, CreatFlags);
1810         SIVAL(vwv+5, 1, 0x0);   /* RootDirectoryFid */
1811         SIVAL(vwv+7, 1, DesiredAccess);
1812         SIVAL(vwv+9, 1, 0x0);   /* AllocationSize */
1813         SIVAL(vwv+11, 1, 0x0);  /* AllocationSize */
1814         SIVAL(vwv+13, 1, FileAttributes);
1815         SIVAL(vwv+15, 1, ShareAccess);
1816         SIVAL(vwv+17, 1, CreateDisposition);
1817         SIVAL(vwv+19, 1, CreateOptions |
1818                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
1819         SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1820         SCVAL(vwv+23, 1, SecurityFlags);
1821
1822         bytes = talloc_array(state, uint8_t, 0);
1823         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
1824                                    fname, strlen(fname)+1,
1825                                    &converted_len);
1826
1827         /* sigh. this copes with broken netapp filer behaviour */
1828         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
1829
1830         if (tevent_req_nomem(bytes, req)) {
1831                 return tevent_req_post(req, ev);
1832         }
1833
1834         SSVAL(vwv+2, 1, converted_len);
1835
1836         subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
1837                               talloc_get_size(bytes), bytes);
1838         if (tevent_req_nomem(subreq, req)) {
1839                 return tevent_req_post(req, ev);
1840         }
1841         tevent_req_set_callback(subreq, cli_ntcreate_done, req);
1842         return req;
1843 }
1844
1845 static void cli_ntcreate_done(struct tevent_req *subreq)
1846 {
1847         struct tevent_req *req = tevent_req_callback_data(
1848                 subreq, struct tevent_req);
1849         struct cli_ntcreate_state *state = tevent_req_data(
1850                 req, struct cli_ntcreate_state);
1851         uint8_t wct;
1852         uint16_t *vwv;
1853         uint32_t num_bytes;
1854         uint8_t *bytes;
1855         NTSTATUS status;
1856
1857         status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv,
1858                               &num_bytes, &bytes);
1859         TALLOC_FREE(subreq);
1860         if (tevent_req_nterror(req, status)) {
1861                 return;
1862         }
1863         state->fnum = SVAL(vwv+2, 1);
1864         tevent_req_done(req);
1865 }
1866
1867 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
1868 {
1869         struct cli_ntcreate_state *state = tevent_req_data(
1870                 req, struct cli_ntcreate_state);
1871         NTSTATUS status;
1872
1873         if (tevent_req_is_nterror(req, &status)) {
1874                 return status;
1875         }
1876         *pfnum = state->fnum;
1877         return NT_STATUS_OK;
1878 }
1879
1880 NTSTATUS cli_ntcreate(struct cli_state *cli,
1881                       const char *fname,
1882                       uint32_t CreatFlags,
1883                       uint32_t DesiredAccess,
1884                       uint32_t FileAttributes,
1885                       uint32_t ShareAccess,
1886                       uint32_t CreateDisposition,
1887                       uint32_t CreateOptions,
1888                       uint8_t SecurityFlags,
1889                       uint16_t *pfid)
1890 {
1891         TALLOC_CTX *frame = talloc_stackframe();
1892         struct tevent_context *ev;
1893         struct tevent_req *req;
1894         NTSTATUS status = NT_STATUS_OK;
1895
1896         if (smbXcli_conn_has_async_calls(cli->conn)) {
1897                 /*
1898                  * Can't use sync call while an async call is in flight
1899                  */
1900                 status = NT_STATUS_INVALID_PARAMETER;
1901                 goto fail;
1902         }
1903
1904         ev = samba_tevent_context_init(frame);
1905         if (ev == NULL) {
1906                 status = NT_STATUS_NO_MEMORY;
1907                 goto fail;
1908         }
1909
1910         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
1911                                 DesiredAccess, FileAttributes, ShareAccess,
1912                                 CreateDisposition, CreateOptions,
1913                                 SecurityFlags);
1914         if (req == NULL) {
1915                 status = NT_STATUS_NO_MEMORY;
1916                 goto fail;
1917         }
1918
1919         if (!tevent_req_poll(req, ev)) {
1920                 status = map_nt_error_from_unix(errno);
1921                 goto fail;
1922         }
1923
1924         status = cli_ntcreate_recv(req, pfid);
1925  fail:
1926         TALLOC_FREE(frame);
1927         return status;
1928 }
1929
1930 struct cli_nttrans_create_state {
1931         uint16_t fnum;
1932 };
1933
1934 static void cli_nttrans_create_done(struct tevent_req *subreq);
1935
1936 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
1937                                            struct tevent_context *ev,
1938                                            struct cli_state *cli,
1939                                            const char *fname,
1940                                            uint32_t CreatFlags,
1941                                            uint32_t DesiredAccess,
1942                                            uint32_t FileAttributes,
1943                                            uint32_t ShareAccess,
1944                                            uint32_t CreateDisposition,
1945                                            uint32_t CreateOptions,
1946                                            uint8_t SecurityFlags,
1947                                            struct security_descriptor *secdesc,
1948                                            struct ea_struct *eas,
1949                                            int num_eas)
1950 {
1951         struct tevent_req *req, *subreq;
1952         struct cli_nttrans_create_state *state;
1953         uint8_t *param;
1954         uint8_t *secdesc_buf;
1955         size_t secdesc_len;
1956         NTSTATUS status;
1957         size_t converted_len;
1958
1959         req = tevent_req_create(mem_ctx,
1960                                 &state, struct cli_nttrans_create_state);
1961         if (req == NULL) {
1962                 return NULL;
1963         }
1964
1965         if (secdesc != NULL) {
1966                 status = marshall_sec_desc(talloc_tos(), secdesc,
1967                                            &secdesc_buf, &secdesc_len);
1968                 if (tevent_req_nterror(req, status)) {
1969                         DEBUG(10, ("marshall_sec_desc failed: %s\n",
1970                                    nt_errstr(status)));
1971                         return tevent_req_post(req, ev);
1972                 }
1973         } else {
1974                 secdesc_buf = NULL;
1975                 secdesc_len = 0;
1976         }
1977
1978         if (num_eas != 0) {
1979                 /*
1980                  * TODO ;-)
1981                  */
1982                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1983                 return tevent_req_post(req, ev);
1984         }
1985
1986         param = talloc_array(state, uint8_t, 53);
1987         if (tevent_req_nomem(param, req)) {
1988                 return tevent_req_post(req, ev);
1989         }
1990
1991         param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
1992                                       fname, strlen(fname),
1993                                       &converted_len);
1994         if (tevent_req_nomem(param, req)) {
1995                 return tevent_req_post(req, ev);
1996         }
1997
1998         SIVAL(param, 0, CreatFlags);
1999         SIVAL(param, 4, 0x0);   /* RootDirectoryFid */
2000         SIVAL(param, 8, DesiredAccess);
2001         SIVAL(param, 12, 0x0);  /* AllocationSize */
2002         SIVAL(param, 16, 0x0);  /* AllocationSize */
2003         SIVAL(param, 20, FileAttributes);
2004         SIVAL(param, 24, ShareAccess);
2005         SIVAL(param, 28, CreateDisposition);
2006         SIVAL(param, 32, CreateOptions |
2007                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2008         SIVAL(param, 36, secdesc_len);
2009         SIVAL(param, 40, 0);     /* EA length*/
2010         SIVAL(param, 44, converted_len);
2011         SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2012         SCVAL(param, 52, SecurityFlags);
2013
2014         subreq = cli_trans_send(state, ev, cli, SMBnttrans,
2015                                 NULL, -1, /* name, fid */
2016                                 NT_TRANSACT_CREATE, 0,
2017                                 NULL, 0, 0, /* setup */
2018                                 param, talloc_get_size(param), 128, /* param */
2019                                 secdesc_buf, secdesc_len, 0); /* data */
2020         if (tevent_req_nomem(subreq, req)) {
2021                 return tevent_req_post(req, ev);
2022         }
2023         tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2024         return req;
2025 }
2026
2027 static void cli_nttrans_create_done(struct tevent_req *subreq)
2028 {
2029         struct tevent_req *req = tevent_req_callback_data(
2030                 subreq, struct tevent_req);
2031         struct cli_nttrans_create_state *state = tevent_req_data(
2032                 req, struct cli_nttrans_create_state);
2033         uint8_t *param;
2034         uint32_t num_param;
2035         NTSTATUS status;
2036
2037         status = cli_trans_recv(subreq, talloc_tos(), NULL,
2038                                 NULL, 0, NULL, /* rsetup */
2039                                 &param, 69, &num_param,
2040                                 NULL, 0, NULL);
2041         if (tevent_req_nterror(req, status)) {
2042                 return;
2043         }
2044         state->fnum = SVAL(param, 2);
2045         TALLOC_FREE(param);
2046         tevent_req_done(req);
2047 }
2048
2049 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req, uint16_t *fnum)
2050 {
2051         struct cli_nttrans_create_state *state = tevent_req_data(
2052                 req, struct cli_nttrans_create_state);
2053         NTSTATUS status;
2054
2055         if (tevent_req_is_nterror(req, &status)) {
2056                 return status;
2057         }
2058         *fnum = state->fnum;
2059         return NT_STATUS_OK;
2060 }
2061
2062 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2063                             const char *fname,
2064                             uint32_t CreatFlags,
2065                             uint32_t DesiredAccess,
2066                             uint32_t FileAttributes,
2067                             uint32_t ShareAccess,
2068                             uint32_t CreateDisposition,
2069                             uint32_t CreateOptions,
2070                             uint8_t SecurityFlags,
2071                             struct security_descriptor *secdesc,
2072                             struct ea_struct *eas,
2073                             int num_eas,
2074                             uint16_t *pfid)
2075 {
2076         TALLOC_CTX *frame = talloc_stackframe();
2077         struct tevent_context *ev;
2078         struct tevent_req *req;
2079         NTSTATUS status = NT_STATUS_NO_MEMORY;
2080
2081         if (smbXcli_conn_has_async_calls(cli->conn)) {
2082                 /*
2083                  * Can't use sync call while an async call is in flight
2084                  */
2085                 status = NT_STATUS_INVALID_PARAMETER;
2086                 goto fail;
2087         }
2088         ev = samba_tevent_context_init(frame);
2089         if (ev == NULL) {
2090                 goto fail;
2091         }
2092         req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2093                                       DesiredAccess, FileAttributes,
2094                                       ShareAccess, CreateDisposition,
2095                                       CreateOptions, SecurityFlags,
2096                                       secdesc, eas, num_eas);
2097         if (req == NULL) {
2098                 goto fail;
2099         }
2100         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2101                 goto fail;
2102         }
2103         status = cli_nttrans_create_recv(req, pfid);
2104  fail:
2105         TALLOC_FREE(frame);
2106         return status;
2107 }
2108
2109 /****************************************************************************
2110  Open a file
2111  WARNING: if you open with O_WRONLY then getattrE won't work!
2112 ****************************************************************************/
2113
2114 struct cli_openx_state {
2115         const char *fname;
2116         uint16_t vwv[15];
2117         uint16_t fnum;
2118         struct iovec bytes;
2119 };
2120
2121 static void cli_openx_done(struct tevent_req *subreq);
2122
2123 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2124                                    struct tevent_context *ev,
2125                                    struct cli_state *cli, const char *fname,
2126                                    int flags, int share_mode,
2127                                    struct tevent_req **psmbreq)
2128 {
2129         struct tevent_req *req, *subreq;
2130         struct cli_openx_state *state;
2131         unsigned openfn;
2132         unsigned accessmode;
2133         uint8_t additional_flags;
2134         uint8_t *bytes;
2135
2136         req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2137         if (req == NULL) {
2138                 return NULL;
2139         }
2140
2141         openfn = 0;
2142         if (flags & O_CREAT) {
2143                 openfn |= (1<<4);
2144         }
2145         if (!(flags & O_EXCL)) {
2146                 if (flags & O_TRUNC)
2147                         openfn |= (1<<1);
2148                 else
2149                         openfn |= (1<<0);
2150         }
2151
2152         accessmode = (share_mode<<4);
2153
2154         if ((flags & O_ACCMODE) == O_RDWR) {
2155                 accessmode |= 2;
2156         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2157                 accessmode |= 1;
2158         }
2159
2160 #if defined(O_SYNC)
2161         if ((flags & O_SYNC) == O_SYNC) {
2162                 accessmode |= (1<<14);
2163         }
2164 #endif /* O_SYNC */
2165
2166         if (share_mode == DENY_FCB) {
2167                 accessmode = 0xFF;
2168         }
2169
2170         SCVAL(state->vwv + 0, 0, 0xFF);
2171         SCVAL(state->vwv + 0, 1, 0);
2172         SSVAL(state->vwv + 1, 0, 0);
2173         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
2174         SSVAL(state->vwv + 3, 0, accessmode);
2175         SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2176         SSVAL(state->vwv + 5, 0, 0);
2177         SIVAL(state->vwv + 6, 0, 0);
2178         SSVAL(state->vwv + 8, 0, openfn);
2179         SIVAL(state->vwv + 9, 0, 0);
2180         SIVAL(state->vwv + 11, 0, 0);
2181         SIVAL(state->vwv + 13, 0, 0);
2182
2183         additional_flags = 0;
2184
2185         if (cli->use_oplocks) {
2186                 /* if using oplocks then ask for a batch oplock via
2187                    core and extended methods */
2188                 additional_flags =
2189                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2190                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2191         }
2192
2193         bytes = talloc_array(state, uint8_t, 0);
2194         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2195                                    strlen(fname)+1, NULL);
2196
2197         if (tevent_req_nomem(bytes, req)) {
2198                 return tevent_req_post(req, ev);
2199         }
2200
2201         state->bytes.iov_base = (void *)bytes;
2202         state->bytes.iov_len = talloc_get_size(bytes);
2203
2204         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2205                                     15, state->vwv, 1, &state->bytes);
2206         if (subreq == NULL) {
2207                 TALLOC_FREE(req);
2208                 return NULL;
2209         }
2210         tevent_req_set_callback(subreq, cli_openx_done, req);
2211         *psmbreq = subreq;
2212         return req;
2213 }
2214
2215 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2216                                  struct cli_state *cli, const char *fname,
2217                                  int flags, int share_mode)
2218 {
2219         struct tevent_req *req, *subreq;
2220         NTSTATUS status;
2221
2222         req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
2223                               &subreq);
2224         if (req == NULL) {
2225                 return NULL;
2226         }
2227
2228         status = smb1cli_req_chain_submit(&subreq, 1);
2229         if (tevent_req_nterror(req, status)) {
2230                 return tevent_req_post(req, ev);
2231         }
2232         return req;
2233 }
2234
2235 static void cli_openx_done(struct tevent_req *subreq)
2236 {
2237         struct tevent_req *req = tevent_req_callback_data(
2238                 subreq, struct tevent_req);
2239         struct cli_openx_state *state = tevent_req_data(
2240                 req, struct cli_openx_state);
2241         uint8_t wct;
2242         uint16_t *vwv;
2243         NTSTATUS status;
2244
2245         status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
2246                               NULL);
2247         TALLOC_FREE(subreq);
2248         if (tevent_req_nterror(req, status)) {
2249                 return;
2250         }
2251         state->fnum = SVAL(vwv+2, 0);
2252         tevent_req_done(req);
2253 }
2254
2255 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2256 {
2257         struct cli_openx_state *state = tevent_req_data(
2258                 req, struct cli_openx_state);
2259         NTSTATUS status;
2260
2261         if (tevent_req_is_nterror(req, &status)) {
2262                 return status;
2263         }
2264         *pfnum = state->fnum;
2265         return NT_STATUS_OK;
2266 }
2267
2268 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
2269              int share_mode, uint16_t *pfnum)
2270 {
2271         TALLOC_CTX *frame = talloc_stackframe();
2272         struct tevent_context *ev;
2273         struct tevent_req *req;
2274         NTSTATUS status = NT_STATUS_OK;
2275
2276         if (smbXcli_conn_has_async_calls(cli->conn)) {
2277                 /*
2278                  * Can't use sync call while an async call is in flight
2279                  */
2280                 status = NT_STATUS_INVALID_PARAMETER;
2281                 goto fail;
2282         }
2283
2284         ev = samba_tevent_context_init(frame);
2285         if (ev == NULL) {
2286                 status = NT_STATUS_NO_MEMORY;
2287                 goto fail;
2288         }
2289
2290         req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
2291         if (req == NULL) {
2292                 status = NT_STATUS_NO_MEMORY;
2293                 goto fail;
2294         }
2295
2296         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2297                 goto fail;
2298         }
2299
2300         status = cli_openx_recv(req, pfnum);
2301  fail:
2302         TALLOC_FREE(frame);
2303         return status;
2304 }
2305 /****************************************************************************
2306  Synchronous wrapper function that does an NtCreateX open by preference
2307  and falls back to openX if this fails.
2308 ****************************************************************************/
2309
2310 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2311                         int share_mode_in, uint16_t *pfnum)
2312 {
2313         NTSTATUS status;
2314         unsigned int openfn = 0;
2315         unsigned int dos_deny = 0;
2316         uint32_t access_mask, share_mode, create_disposition, create_options;
2317
2318         /* Do the initial mapping into OpenX parameters. */
2319         if (flags & O_CREAT) {
2320                 openfn |= (1<<4);
2321         }
2322         if (!(flags & O_EXCL)) {
2323                 if (flags & O_TRUNC)
2324                         openfn |= (1<<1);
2325                 else
2326                         openfn |= (1<<0);
2327         }
2328
2329         dos_deny = (share_mode_in<<4);
2330
2331         if ((flags & O_ACCMODE) == O_RDWR) {
2332                 dos_deny |= 2;
2333         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2334                 dos_deny |= 1;
2335         }
2336
2337 #if defined(O_SYNC)
2338         if ((flags & O_SYNC) == O_SYNC) {
2339                 dos_deny |= (1<<14);
2340         }
2341 #endif /* O_SYNC */
2342
2343         if (share_mode_in == DENY_FCB) {
2344                 dos_deny = 0xFF;
2345         }
2346
2347 #if 0
2348         /* Hmmm. This is what I think the above code
2349            should look like if it's using the constants
2350            we #define. JRA. */
2351
2352         if (flags & O_CREAT) {
2353                 openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
2354         }
2355         if (!(flags & O_EXCL)) {
2356                 if (flags & O_TRUNC)
2357                         openfn |= OPENX_FILE_EXISTS_TRUNCATE;
2358                 else
2359                         openfn |= OPENX_FILE_EXISTS_OPEN;
2360         }
2361
2362         dos_deny = SET_DENY_MODE(share_mode_in);
2363
2364         if ((flags & O_ACCMODE) == O_RDWR) {
2365                 dos_deny |= DOS_OPEN_RDWR;
2366         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2367                 dos_deny |= DOS_OPEN_WRONLY;
2368         }
2369
2370 #if defined(O_SYNC)
2371         if ((flags & O_SYNC) == O_SYNC) {
2372                 dos_deny |= FILE_SYNC_OPENMODE;
2373         }
2374 #endif /* O_SYNC */
2375
2376         if (share_mode_in == DENY_FCB) {
2377                 dos_deny = 0xFF;
2378         }
2379 #endif
2380
2381         if (!map_open_params_to_ntcreate(fname, dos_deny,
2382                                         openfn, &access_mask,
2383                                         &share_mode, &create_disposition,
2384                                         &create_options, NULL)) {
2385                 goto try_openx;
2386         }
2387
2388         status = cli_ntcreate(cli,
2389                                 fname,
2390                                 0,
2391                                 access_mask,
2392                                 0,
2393                                 share_mode,
2394                                 create_disposition,
2395                                 create_options,
2396                                 0,
2397                                 pfnum);
2398
2399         /* Try and cope will all varients of "we don't do this call"
2400            and fall back to openX. */
2401
2402         if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
2403                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
2404                         NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
2405                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
2406                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
2407                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
2408                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
2409                         NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
2410                         NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
2411                 goto try_openx;
2412         }
2413
2414         return status;
2415
2416   try_openx:
2417
2418         return cli_openx(cli, fname, flags, share_mode_in, pfnum);
2419 }
2420
2421 /****************************************************************************
2422  Close a file.
2423 ****************************************************************************/
2424
2425 struct cli_close_state {
2426         uint16_t vwv[3];
2427 };
2428
2429 static void cli_close_done(struct tevent_req *subreq);
2430
2431 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2432                                 struct tevent_context *ev,
2433                                 struct cli_state *cli,
2434                                 uint16_t fnum,
2435                                 struct tevent_req **psubreq)
2436 {
2437         struct tevent_req *req, *subreq;
2438         struct cli_close_state *state;
2439
2440         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2441         if (req == NULL) {
2442                 return NULL;
2443         }
2444
2445         SSVAL(state->vwv+0, 0, fnum);
2446         SIVALS(state->vwv+1, 0, -1);
2447
2448         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2449                                     0, NULL);
2450         if (subreq == NULL) {
2451                 TALLOC_FREE(req);
2452                 return NULL;
2453         }
2454         tevent_req_set_callback(subreq, cli_close_done, req);
2455         *psubreq = subreq;
2456         return req;
2457 }
2458
2459 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2460                                 struct tevent_context *ev,
2461                                 struct cli_state *cli,
2462                                 uint16_t fnum)
2463 {
2464         struct tevent_req *req, *subreq;
2465         NTSTATUS status;
2466
2467         req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2468         if (req == NULL) {
2469                 return NULL;
2470         }
2471
2472         status = smb1cli_req_chain_submit(&subreq, 1);
2473         if (tevent_req_nterror(req, status)) {
2474                 return tevent_req_post(req, ev);
2475         }
2476         return req;
2477 }
2478
2479 static void cli_close_done(struct tevent_req *subreq)
2480 {
2481         struct tevent_req *req = tevent_req_callback_data(
2482                 subreq, struct tevent_req);
2483         NTSTATUS status;
2484
2485         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2486         TALLOC_FREE(subreq);
2487         if (tevent_req_nterror(req, status)) {
2488                 return;
2489         }
2490         tevent_req_done(req);
2491 }
2492
2493 NTSTATUS cli_close_recv(struct tevent_req *req)
2494 {
2495         return tevent_req_simple_recv_ntstatus(req);
2496 }
2497
2498 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2499 {
2500         TALLOC_CTX *frame = talloc_stackframe();
2501         struct tevent_context *ev;
2502         struct tevent_req *req;
2503         NTSTATUS status = NT_STATUS_OK;
2504
2505         if (smbXcli_conn_has_async_calls(cli->conn)) {
2506                 /*
2507                  * Can't use sync call while an async call is in flight
2508                  */
2509                 status = NT_STATUS_INVALID_PARAMETER;
2510                 goto fail;
2511         }
2512
2513         ev = samba_tevent_context_init(frame);
2514         if (ev == NULL) {
2515                 status = NT_STATUS_NO_MEMORY;
2516                 goto fail;
2517         }
2518
2519         req = cli_close_send(frame, ev, cli, fnum);
2520         if (req == NULL) {
2521                 status = NT_STATUS_NO_MEMORY;
2522                 goto fail;
2523         }
2524
2525         if (!tevent_req_poll(req, ev)) {
2526                 status = map_nt_error_from_unix(errno);
2527                 goto fail;
2528         }
2529
2530         status = cli_close_recv(req);
2531  fail:
2532         TALLOC_FREE(frame);
2533         return status;
2534 }
2535
2536 /****************************************************************************
2537  Truncate a file to a specified size
2538 ****************************************************************************/
2539
2540 struct ftrunc_state {
2541         uint16_t setup;
2542         uint8_t param[6];
2543         uint8_t data[8];
2544 };
2545
2546 static void cli_ftruncate_done(struct tevent_req *subreq)
2547 {
2548         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2549                                          NULL, 0, NULL, NULL, 0, NULL);
2550         tevent_req_simple_finish_ntstatus(subreq, status);
2551 }
2552
2553 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2554                                         struct tevent_context *ev,
2555                                         struct cli_state *cli,
2556                                         uint16_t fnum,
2557                                         uint64_t size)
2558 {
2559         struct tevent_req *req = NULL, *subreq = NULL;
2560         struct ftrunc_state *state = NULL;
2561
2562         req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2563         if (req == NULL) {
2564                 return NULL;
2565         }
2566
2567         /* Setup setup word. */
2568         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2569
2570         /* Setup param array. */
2571         SSVAL(state->param,0,fnum);
2572         SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2573         SSVAL(state->param,4,0);
2574
2575         /* Setup data array. */
2576         SBVAL(state->data, 0, size);
2577
2578         subreq = cli_trans_send(state,                  /* mem ctx. */
2579                                 ev,                     /* event ctx. */
2580                                 cli,                    /* cli_state. */
2581                                 SMBtrans2,              /* cmd. */
2582                                 NULL,                   /* pipe name. */
2583                                 -1,                     /* fid. */
2584                                 0,                      /* function. */
2585                                 0,                      /* flags. */
2586                                 &state->setup,          /* setup. */
2587                                 1,                      /* num setup uint16_t words. */
2588                                 0,                      /* max returned setup. */
2589                                 state->param,           /* param. */
2590                                 6,                      /* num param. */
2591                                 2,                      /* max returned param. */
2592                                 state->data,            /* data. */
2593                                 8,                      /* num data. */
2594                                 0);                     /* max returned data. */
2595
2596         if (tevent_req_nomem(subreq, req)) {
2597                 return tevent_req_post(req, ev);
2598         }
2599         tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2600         return req;
2601 }
2602
2603 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2604 {
2605         return tevent_req_simple_recv_ntstatus(req);
2606 }
2607
2608 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2609 {
2610         TALLOC_CTX *frame = talloc_stackframe();
2611         struct tevent_context *ev = NULL;
2612         struct tevent_req *req = NULL;
2613         NTSTATUS status = NT_STATUS_OK;
2614
2615         if (smbXcli_conn_has_async_calls(cli->conn)) {
2616                 /*
2617                  * Can't use sync call while an async call is in flight
2618                  */
2619                 status = NT_STATUS_INVALID_PARAMETER;
2620                 goto fail;
2621         }
2622
2623         ev = samba_tevent_context_init(frame);
2624         if (ev == NULL) {
2625                 status = NT_STATUS_NO_MEMORY;
2626                 goto fail;
2627         }
2628
2629         req = cli_ftruncate_send(frame,
2630                                 ev,
2631                                 cli,
2632                                 fnum,
2633                                 size);
2634         if (req == NULL) {
2635                 status = NT_STATUS_NO_MEMORY;
2636                 goto fail;
2637         }
2638
2639         if (!tevent_req_poll(req, ev)) {
2640                 status = map_nt_error_from_unix(errno);
2641                 goto fail;
2642         }
2643
2644         status = cli_ftruncate_recv(req);
2645
2646  fail:
2647         TALLOC_FREE(frame);
2648         return status;
2649 }
2650
2651 /****************************************************************************
2652  send a lock with a specified locktype
2653  this is used for testing LOCKING_ANDX_CANCEL_LOCK
2654 ****************************************************************************/
2655
2656 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2657                       uint32_t offset, uint32_t len,
2658                       int timeout, unsigned char locktype)
2659 {
2660         uint16_t vwv[8];
2661         uint8_t bytes[10];
2662         NTSTATUS status;
2663         unsigned int set_timeout = 0;
2664         unsigned int saved_timeout = 0;
2665
2666         SCVAL(vwv + 0, 0, 0xff);
2667         SCVAL(vwv + 0, 1, 0);
2668         SSVAL(vwv + 1, 0, 0);
2669         SSVAL(vwv + 2, 0, fnum);
2670         SCVAL(vwv + 3, 0, locktype);
2671         SCVAL(vwv + 3, 1, 0);
2672         SIVALS(vwv + 4, 0, timeout);
2673         SSVAL(vwv + 6, 0, 0);
2674         SSVAL(vwv + 7, 0, 1);
2675
2676         SSVAL(bytes, 0, cli_getpid(cli));
2677         SIVAL(bytes, 2, offset);
2678         SIVAL(bytes, 6, len);
2679
2680         if (timeout != 0) {
2681                 if (timeout == -1) {
2682                         set_timeout = 0x7FFFFFFF;
2683                 } else {
2684                         set_timeout = timeout + 2*1000;
2685                 }
2686                 saved_timeout = cli_set_timeout(cli, set_timeout);
2687         }
2688
2689         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2690                          10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2691
2692         if (saved_timeout != 0) {
2693                 cli_set_timeout(cli, saved_timeout);
2694         }
2695
2696         return status;
2697 }
2698
2699 /****************************************************************************
2700  Lock a file.
2701  note that timeout is in units of 2 milliseconds
2702 ****************************************************************************/
2703
2704 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
2705                   uint32_t offset, uint32_t len, int timeout,
2706                   enum brl_type lock_type)
2707 {
2708         NTSTATUS status;
2709
2710         status = cli_locktype(cli, fnum, offset, len, timeout,
2711                               (lock_type == READ_LOCK? 1 : 0));
2712         return status;
2713 }
2714
2715 /****************************************************************************
2716  Unlock a file.
2717 ****************************************************************************/
2718
2719 struct cli_unlock_state {
2720         uint16_t vwv[8];
2721         uint8_t data[10];
2722 };
2723
2724 static void cli_unlock_done(struct tevent_req *subreq);
2725
2726 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
2727                                 struct tevent_context *ev,
2728                                 struct cli_state *cli,
2729                                 uint16_t fnum,
2730                                 uint64_t offset,
2731                                 uint64_t len)
2732
2733 {
2734         struct tevent_req *req = NULL, *subreq = NULL;
2735         struct cli_unlock_state *state = NULL;
2736         uint8_t additional_flags = 0;
2737
2738         req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
2739         if (req == NULL) {
2740                 return NULL;
2741         }
2742
2743         SCVAL(state->vwv+0, 0, 0xFF);
2744         SSVAL(state->vwv+2, 0, fnum);
2745         SCVAL(state->vwv+3, 0, 0);
2746         SIVALS(state->vwv+4, 0, 0);
2747         SSVAL(state->vwv+6, 0, 1);
2748         SSVAL(state->vwv+7, 0, 0);
2749
2750         SSVAL(state->data, 0, cli_getpid(cli));
2751         SIVAL(state->data, 2, offset);
2752         SIVAL(state->data, 6, len);
2753
2754         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2755                                 8, state->vwv, 10, state->data);
2756         if (tevent_req_nomem(subreq, req)) {
2757                 return tevent_req_post(req, ev);
2758         }
2759         tevent_req_set_callback(subreq, cli_unlock_done, req);
2760         return req;
2761 }
2762
2763 static void cli_unlock_done(struct tevent_req *subreq)
2764 {
2765         struct tevent_req *req = tevent_req_callback_data(
2766                                 subreq, struct tevent_req);
2767         NTSTATUS status;
2768
2769         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2770         TALLOC_FREE(subreq);
2771         if (tevent_req_nterror(req, status)) {
2772                 return;
2773         }
2774         tevent_req_done(req);
2775 }
2776
2777 NTSTATUS cli_unlock_recv(struct tevent_req *req)
2778 {
2779         return tevent_req_simple_recv_ntstatus(req);
2780 }
2781
2782 NTSTATUS cli_unlock(struct cli_state *cli,
2783                         uint16_t fnum,
2784                         uint32_t offset,
2785                         uint32_t len)
2786 {
2787         TALLOC_CTX *frame = talloc_stackframe();
2788         struct tevent_context *ev;
2789         struct tevent_req *req;
2790         NTSTATUS status = NT_STATUS_OK;
2791
2792         if (smbXcli_conn_has_async_calls(cli->conn)) {
2793                 /*
2794                  * Can't use sync call while an async call is in flight
2795                  */
2796                 status = NT_STATUS_INVALID_PARAMETER;
2797                 goto fail;
2798         }
2799
2800         ev = samba_tevent_context_init(frame);
2801         if (ev == NULL) {
2802                 status = NT_STATUS_NO_MEMORY;
2803                 goto fail;
2804         }
2805
2806         req = cli_unlock_send(frame, ev, cli,
2807                         fnum, offset, len);
2808         if (req == NULL) {
2809                 status = NT_STATUS_NO_MEMORY;
2810                 goto fail;
2811         }
2812
2813         if (!tevent_req_poll(req, ev)) {
2814                 status = map_nt_error_from_unix(errno);
2815                 goto fail;
2816         }
2817
2818         status = cli_unlock_recv(req);
2819
2820  fail:
2821         TALLOC_FREE(frame);
2822         return status;
2823 }
2824
2825 /****************************************************************************
2826  Lock a file with 64 bit offsets.
2827 ****************************************************************************/
2828
2829 NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
2830                     uint64_t offset, uint64_t len, int timeout,
2831                     enum brl_type lock_type)
2832 {
2833         uint16_t vwv[8];
2834         uint8_t bytes[20];
2835         unsigned int set_timeout = 0;
2836         unsigned int saved_timeout = 0;
2837         int ltype;
2838         NTSTATUS status;
2839
2840         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
2841                 return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
2842         }
2843
2844         ltype = (lock_type == READ_LOCK? 1 : 0);
2845         ltype |= LOCKING_ANDX_LARGE_FILES;
2846
2847         SCVAL(vwv + 0, 0, 0xff);
2848         SCVAL(vwv + 0, 1, 0);
2849         SSVAL(vwv + 1, 0, 0);
2850         SSVAL(vwv + 2, 0, fnum);
2851         SCVAL(vwv + 3, 0, ltype);
2852         SCVAL(vwv + 3, 1, 0);
2853         SIVALS(vwv + 4, 0, timeout);
2854         SSVAL(vwv + 6, 0, 0);
2855         SSVAL(vwv + 7, 0, 1);
2856
2857         SIVAL(bytes, 0, cli_getpid(cli));
2858         SOFF_T_R(bytes, 4, offset);
2859         SOFF_T_R(bytes, 12, len);
2860
2861         if (timeout != 0) {
2862                 if (timeout == -1) {
2863                         set_timeout = 0x7FFFFFFF;
2864                 } else {
2865                         set_timeout = timeout + 2*1000;
2866                 }
2867                 saved_timeout = cli_set_timeout(cli, set_timeout);
2868         }
2869
2870         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2871                          20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2872
2873         if (saved_timeout != 0) {
2874                 cli_set_timeout(cli, saved_timeout);
2875         }
2876
2877         return status;
2878 }
2879
2880 /****************************************************************************
2881  Unlock a file with 64 bit offsets.
2882 ****************************************************************************/
2883
2884 struct cli_unlock64_state {
2885         uint16_t vwv[8];
2886         uint8_t data[20];
2887 };
2888
2889 static void cli_unlock64_done(struct tevent_req *subreq);
2890
2891 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
2892                                 struct tevent_context *ev,
2893                                 struct cli_state *cli,
2894                                 uint16_t fnum,
2895                                 uint64_t offset,
2896                                 uint64_t len)
2897
2898 {
2899         struct tevent_req *req = NULL, *subreq = NULL;
2900         struct cli_unlock64_state *state = NULL;
2901         uint8_t additional_flags = 0;
2902
2903         req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
2904         if (req == NULL) {
2905                 return NULL;
2906         }
2907
2908         SCVAL(state->vwv+0, 0, 0xff);
2909         SSVAL(state->vwv+2, 0, fnum);
2910         SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
2911         SIVALS(state->vwv+4, 0, 0);
2912         SSVAL(state->vwv+6, 0, 1);
2913         SSVAL(state->vwv+7, 0, 0);
2914
2915         SIVAL(state->data, 0, cli_getpid(cli));
2916         SOFF_T_R(state->data, 4, offset);
2917         SOFF_T_R(state->data, 12, len);
2918
2919         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2920                                 8, state->vwv, 20, state->data);
2921         if (tevent_req_nomem(subreq, req)) {
2922                 return tevent_req_post(req, ev);
2923         }
2924         tevent_req_set_callback(subreq, cli_unlock64_done, req);
2925         return req;
2926 }
2927
2928 static void cli_unlock64_done(struct tevent_req *subreq)
2929 {
2930         struct tevent_req *req = tevent_req_callback_data(
2931                                 subreq, struct tevent_req);
2932         NTSTATUS status;
2933
2934         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2935         TALLOC_FREE(subreq);
2936         if (tevent_req_nterror(req, status)) {
2937                 return;
2938         }
2939         tevent_req_done(req);
2940 }
2941
2942 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
2943 {
2944         return tevent_req_simple_recv_ntstatus(req);
2945 }
2946
2947 NTSTATUS cli_unlock64(struct cli_state *cli,
2948                                 uint16_t fnum,
2949                                 uint64_t offset,
2950                                 uint64_t len)
2951 {
2952         TALLOC_CTX *frame = talloc_stackframe();
2953         struct tevent_context *ev;
2954         struct tevent_req *req;
2955         NTSTATUS status = NT_STATUS_OK;
2956
2957         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
2958                 return cli_unlock(cli, fnum, offset, len);
2959         }
2960
2961         if (smbXcli_conn_has_async_calls(cli->conn)) {
2962                 /*
2963                  * Can't use sync call while an async call is in flight
2964                  */
2965                 status = NT_STATUS_INVALID_PARAMETER;
2966                 goto fail;
2967         }
2968
2969         ev = samba_tevent_context_init(frame);
2970         if (ev == NULL) {
2971                 status = NT_STATUS_NO_MEMORY;
2972                 goto fail;
2973         }
2974
2975         req = cli_unlock64_send(frame, ev, cli,
2976                         fnum, offset, len);
2977         if (req == NULL) {
2978                 status = NT_STATUS_NO_MEMORY;
2979                 goto fail;
2980         }
2981
2982         if (!tevent_req_poll(req, ev)) {
2983                 status = map_nt_error_from_unix(errno);
2984                 goto fail;
2985         }
2986
2987         status = cli_unlock64_recv(req);
2988
2989  fail:
2990         TALLOC_FREE(frame);
2991         return status;
2992 }
2993
2994 /****************************************************************************
2995  Get/unlock a POSIX lock on a file - internal function.
2996 ****************************************************************************/
2997
2998 struct posix_lock_state {
2999         uint16_t setup;
3000         uint8_t param[4];
3001         uint8_t data[POSIX_LOCK_DATA_SIZE];
3002 };
3003
3004 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3005 {
3006         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3007                                          NULL, 0, NULL, NULL, 0, NULL);
3008         tevent_req_simple_finish_ntstatus(subreq, status);
3009 }
3010
3011 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3012                                         struct tevent_context *ev,
3013                                         struct cli_state *cli,
3014                                         uint16_t fnum,
3015                                         uint64_t offset,
3016                                         uint64_t len,
3017                                         bool wait_lock,
3018                                         enum brl_type lock_type)
3019 {
3020         struct tevent_req *req = NULL, *subreq = NULL;
3021         struct posix_lock_state *state = NULL;
3022
3023         req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3024         if (req == NULL) {
3025                 return NULL;
3026         }
3027
3028         /* Setup setup word. */
3029         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3030
3031         /* Setup param array. */
3032         SSVAL(&state->param, 0, fnum);
3033         SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3034
3035         /* Setup data array. */
3036         switch (lock_type) {
3037                 case READ_LOCK:
3038                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3039                                 POSIX_LOCK_TYPE_READ);
3040                         break;
3041                 case WRITE_LOCK:
3042                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3043                                 POSIX_LOCK_TYPE_WRITE);
3044                         break;
3045                 case UNLOCK_LOCK:
3046                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3047                                 POSIX_LOCK_TYPE_UNLOCK);
3048                         break;
3049                 default:
3050                         return NULL;
3051         }
3052
3053         if (wait_lock) {
3054                 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3055                                 POSIX_LOCK_FLAG_WAIT);
3056         } else {
3057                 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3058                                 POSIX_LOCK_FLAG_NOWAIT);
3059         }
3060
3061         SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3062         SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3063         SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3064
3065         subreq = cli_trans_send(state,                  /* mem ctx. */
3066                                 ev,                     /* event ctx. */
3067                                 cli,                    /* cli_state. */
3068                                 SMBtrans2,              /* cmd. */
3069                                 NULL,                   /* pipe name. */
3070                                 -1,                     /* fid. */
3071                                 0,                      /* function. */
3072                                 0,                      /* flags. */
3073                                 &state->setup,          /* setup. */
3074                                 1,                      /* num setup uint16_t words. */
3075                                 0,                      /* max returned setup. */
3076                                 state->param,           /* param. */
3077                                 4,                      /* num param. */
3078                                 2,                      /* max returned param. */
3079                                 state->data,            /* data. */
3080                                 POSIX_LOCK_DATA_SIZE,   /* num data. */
3081                                 0);                     /* max returned data. */
3082
3083         if (tevent_req_nomem(subreq, req)) {
3084                 return tevent_req_post(req, ev);
3085         }
3086         tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3087         return req;
3088 }
3089
3090 /****************************************************************************
3091  POSIX Lock a file.
3092 ****************************************************************************/
3093
3094 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3095                                         struct tevent_context *ev,
3096                                         struct cli_state *cli,
3097                                         uint16_t fnum,
3098                                         uint64_t offset,
3099                                         uint64_t len,
3100                                         bool wait_lock,
3101                                         enum brl_type lock_type)
3102 {
3103         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3104                                         wait_lock, lock_type);
3105 }
3106
3107 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3108 {
3109         return tevent_req_simple_recv_ntstatus(req);
3110 }
3111
3112 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3113                         uint64_t offset, uint64_t len,
3114                         bool wait_lock, enum brl_type lock_type)
3115 {
3116         TALLOC_CTX *frame = talloc_stackframe();
3117         struct tevent_context *ev = NULL;
3118         struct tevent_req *req = NULL;
3119         NTSTATUS status = NT_STATUS_OK;
3120
3121         if (smbXcli_conn_has_async_calls(cli->conn)) {
3122                 /*
3123                  * Can't use sync call while an async call is in flight
3124                  */
3125                 status = NT_STATUS_INVALID_PARAMETER;
3126                 goto fail;
3127         }
3128
3129         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3130                 status = NT_STATUS_INVALID_PARAMETER;
3131                 goto fail;
3132         }
3133
3134         ev = samba_tevent_context_init(frame);
3135         if (ev == NULL) {
3136                 status = NT_STATUS_NO_MEMORY;
3137                 goto fail;
3138         }
3139
3140         req = cli_posix_lock_send(frame,
3141                                 ev,
3142                                 cli,
3143                                 fnum,
3144                                 offset,
3145                                 len,
3146                                 wait_lock,
3147                                 lock_type);
3148         if (req == NULL) {
3149                 status = NT_STATUS_NO_MEMORY;
3150                 goto fail;
3151         }
3152
3153         if (!tevent_req_poll(req, ev)) {
3154                 status = map_nt_error_from_unix(errno);
3155                 goto fail;
3156         }
3157
3158         status = cli_posix_lock_recv(req);
3159
3160  fail:
3161         TALLOC_FREE(frame);
3162         return status;
3163 }
3164
3165 /****************************************************************************
3166  POSIX Unlock a file.
3167 ****************************************************************************/
3168
3169 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3170                                         struct tevent_context *ev,
3171                                         struct cli_state *cli,
3172                                         uint16_t fnum,
3173                                         uint64_t offset,
3174                                         uint64_t len)
3175 {
3176         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3177                                         false, UNLOCK_LOCK);
3178 }
3179
3180 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3181 {
3182         return tevent_req_simple_recv_ntstatus(req);
3183 }
3184
3185 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3186 {
3187         TALLOC_CTX *frame = talloc_stackframe();
3188         struct tevent_context *ev = NULL;
3189         struct tevent_req *req = NULL;
3190         NTSTATUS status = NT_STATUS_OK;
3191
3192         if (smbXcli_conn_has_async_calls(cli->conn)) {
3193                 /*
3194                  * Can't use sync call while an async call is in flight
3195                  */
3196                 status = NT_STATUS_INVALID_PARAMETER;
3197                 goto fail;
3198         }
3199
3200         ev = samba_tevent_context_init(frame);
3201         if (ev == NULL) {
3202                 status = NT_STATUS_NO_MEMORY;
3203                 goto fail;
3204         }
3205
3206         req = cli_posix_unlock_send(frame,
3207                                 ev,
3208                                 cli,
3209                                 fnum,
3210                                 offset,
3211                                 len);
3212         if (req == NULL) {
3213                 status = NT_STATUS_NO_MEMORY;
3214                 goto fail;
3215         }
3216
3217         if (!tevent_req_poll(req, ev)) {
3218                 status = map_nt_error_from_unix(errno);
3219                 goto fail;
3220         }
3221
3222         status = cli_posix_unlock_recv(req);
3223
3224  fail:
3225         TALLOC_FREE(frame);
3226         return status;
3227 }
3228
3229 /****************************************************************************
3230  Do a SMBgetattrE call.
3231 ****************************************************************************/
3232
3233 static void cli_getattrE_done(struct tevent_req *subreq);
3234
3235 struct cli_getattrE_state {
3236         uint16_t vwv[1];
3237         int zone_offset;
3238         uint16_t attr;
3239         off_t size;
3240         time_t change_time;
3241         time_t access_time;
3242         time_t write_time;
3243 };
3244
3245 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3246                                 struct tevent_context *ev,
3247                                 struct cli_state *cli,
3248                                 uint16_t fnum)
3249 {
3250         struct tevent_req *req = NULL, *subreq = NULL;
3251         struct cli_getattrE_state *state = NULL;
3252         uint8_t additional_flags = 0;
3253
3254         req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3255         if (req == NULL) {
3256                 return NULL;
3257         }
3258
3259         state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3260         SSVAL(state->vwv+0,0,fnum);
3261
3262         subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
3263                               1, state->vwv, 0, NULL);
3264         if (tevent_req_nomem(subreq, req)) {
3265                 return tevent_req_post(req, ev);
3266         }
3267         tevent_req_set_callback(subreq, cli_getattrE_done, req);
3268         return req;
3269 }
3270
3271 static void cli_getattrE_done(struct tevent_req *subreq)
3272 {
3273         struct tevent_req *req = tevent_req_callback_data(
3274                 subreq, struct tevent_req);
3275         struct cli_getattrE_state *state = tevent_req_data(
3276                 req, struct cli_getattrE_state);
3277         uint8_t wct;
3278         uint16_t *vwv = NULL;
3279         NTSTATUS status;
3280
3281         status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
3282                               NULL, NULL);
3283         TALLOC_FREE(subreq);
3284         if (tevent_req_nterror(req, status)) {
3285                 return;
3286         }
3287
3288         state->size = (off_t)IVAL(vwv+6,0);
3289         state->attr = SVAL(vwv+10,0);
3290         state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3291         state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3292         state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3293
3294         tevent_req_done(req);
3295 }
3296
3297 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3298                         uint16_t *attr,
3299                         off_t *size,
3300                         time_t *change_time,
3301                         time_t *access_time,
3302                         time_t *write_time)
3303 {
3304         struct cli_getattrE_state *state = tevent_req_data(
3305                                 req, struct cli_getattrE_state);
3306         NTSTATUS status;
3307
3308         if (tevent_req_is_nterror(req, &status)) {
3309                 return status;
3310         }
3311         if (attr) {
3312                 *attr = state->attr;
3313         }
3314         if (size) {
3315                 *size = state->size;
3316         }
3317         if (change_time) {
3318                 *change_time = state->change_time;
3319         }
3320         if (access_time) {
3321                 *access_time = state->access_time;
3322         }
3323         if (write_time) {
3324                 *write_time = state->write_time;
3325         }
3326         return NT_STATUS_OK;
3327 }
3328
3329 NTSTATUS cli_getattrE(struct cli_state *cli,
3330                         uint16_t fnum,
3331                         uint16_t *attr,
3332                         off_t *size,
3333                         time_t *change_time,
3334                         time_t *access_time,
3335                         time_t *write_time)
3336 {
3337         TALLOC_CTX *frame = talloc_stackframe();
3338         struct tevent_context *ev = NULL;
3339         struct tevent_req *req = NULL;
3340         NTSTATUS status = NT_STATUS_OK;
3341
3342         if (smbXcli_conn_has_async_calls(cli->conn)) {
3343                 /*
3344                  * Can't use sync call while an async call is in flight
3345                  */
3346                 status = NT_STATUS_INVALID_PARAMETER;
3347                 goto fail;
3348         }
3349
3350         ev = samba_tevent_context_init(frame);
3351         if (ev == NULL) {
3352                 status = NT_STATUS_NO_MEMORY;
3353                 goto fail;
3354         }
3355
3356         req = cli_getattrE_send(frame, ev, cli, fnum);
3357         if (req == NULL) {
3358                 status = NT_STATUS_NO_MEMORY;
3359                 goto fail;
3360         }
3361
3362         if (!tevent_req_poll(req, ev)) {
3363                 status = map_nt_error_from_unix(errno);
3364                 goto fail;
3365         }
3366
3367         status = cli_getattrE_recv(req,
3368                                         attr,
3369                                         size,
3370                                         change_time,
3371                                         access_time,
3372                                         write_time);
3373
3374  fail:
3375         TALLOC_FREE(frame);
3376         return status;
3377 }
3378
3379 /****************************************************************************
3380  Do a SMBgetatr call
3381 ****************************************************************************/
3382
3383 static void cli_getatr_done(struct tevent_req *subreq);
3384
3385 struct cli_getatr_state {
3386         int zone_offset;
3387         uint16_t attr;
3388         off_t size;
3389         time_t write_time;
3390 };
3391
3392 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3393                                 struct tevent_context *ev,
3394                                 struct cli_state *cli,
3395                                 const char *fname)
3396 {
3397         struct tevent_req *req = NULL, *subreq = NULL;
3398         struct cli_getatr_state *state = NULL;
3399         uint8_t additional_flags = 0;
3400         uint8_t *bytes = NULL;
3401
3402         req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3403         if (req == NULL) {
3404                 return NULL;
3405         }
3406
3407         state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3408
3409         bytes = talloc_array(state, uint8_t, 1);
3410         if (tevent_req_nomem(bytes, req)) {
3411                 return tevent_req_post(req, ev);
3412         }
3413         bytes[0] = 4;
3414         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3415                                    strlen(fname)+1, NULL);
3416
3417         if (tevent_req_nomem(bytes, req)) {
3418                 return tevent_req_post(req, ev);
3419         }
3420
3421         subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3422                               0, NULL, talloc_get_size(bytes), bytes);
3423         if (tevent_req_nomem(subreq, req)) {
3424                 return tevent_req_post(req, ev);
3425         }
3426         tevent_req_set_callback(subreq, cli_getatr_done, req);
3427         return req;
3428 }
3429
3430 static void cli_getatr_done(struct tevent_req *subreq)
3431 {
3432         struct tevent_req *req = tevent_req_callback_data(
3433                 subreq, struct tevent_req);
3434         struct cli_getatr_state *state = tevent_req_data(
3435                 req, struct cli_getatr_state);
3436         uint8_t wct;
3437         uint16_t *vwv = NULL;
3438         NTSTATUS status;
3439
3440         status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
3441                               NULL);
3442         TALLOC_FREE(subreq);
3443         if (tevent_req_nterror(req, status)) {
3444                 return;
3445         }
3446
3447         state->attr = SVAL(vwv+0,0);
3448         state->size = (off_t)IVAL(vwv+3,0);
3449         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3450
3451         tevent_req_done(req);
3452 }
3453
3454 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3455                         uint16_t *attr,
3456                         off_t *size,
3457                         time_t *write_time)
3458 {
3459         struct cli_getatr_state *state = tevent_req_data(
3460                                 req, struct cli_getatr_state);
3461         NTSTATUS status;
3462
3463         if (tevent_req_is_nterror(req, &status)) {
3464                 return status;
3465         }
3466         if (attr) {
3467                 *attr = state->attr;
3468         }
3469         if (size) {
3470                 *size = state->size;
3471         }
3472         if (write_time) {
3473                 *write_time = state->write_time;
3474         }
3475         return NT_STATUS_OK;
3476 }
3477
3478 NTSTATUS cli_getatr(struct cli_state *cli,
3479                         const char *fname,
3480                         uint16_t *attr,
3481                         off_t *size,
3482                         time_t *write_time)
3483 {
3484         TALLOC_CTX *frame = talloc_stackframe();
3485         struct tevent_context *ev = NULL;
3486         struct tevent_req *req = NULL;
3487         NTSTATUS status = NT_STATUS_OK;
3488
3489         if (smbXcli_conn_has_async_calls(cli->conn)) {
3490                 /*
3491                  * Can't use sync call while an async call is in flight
3492                  */
3493                 status = NT_STATUS_INVALID_PARAMETER;
3494                 goto fail;
3495         }
3496
3497         ev = samba_tevent_context_init(frame);
3498         if (ev == NULL) {
3499                 status = NT_STATUS_NO_MEMORY;
3500                 goto fail;
3501         }
3502
3503         req = cli_getatr_send(frame, ev, cli, fname);
3504         if (req == NULL) {
3505                 status = NT_STATUS_NO_MEMORY;
3506                 goto fail;
3507         }
3508
3509         if (!tevent_req_poll(req, ev)) {
3510                 status = map_nt_error_from_unix(errno);
3511                 goto fail;
3512         }
3513
3514         status = cli_getatr_recv(req,
3515                                 attr,
3516                                 size,
3517                                 write_time);
3518
3519  fail:
3520         TALLOC_FREE(frame);
3521         return status;
3522 }
3523
3524 /****************************************************************************
3525  Do a SMBsetattrE call.
3526 ****************************************************************************/
3527
3528 static void cli_setattrE_done(struct tevent_req *subreq);
3529
3530 struct cli_setattrE_state {
3531         uint16_t vwv[7];
3532 };
3533
3534 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3535                                 struct tevent_context *ev,
3536                                 struct cli_state *cli,
3537                                 uint16_t fnum,
3538                                 time_t change_time,
3539                                 time_t access_time,
3540                                 time_t write_time)
3541 {
3542         struct tevent_req *req = NULL, *subreq = NULL;
3543         struct cli_setattrE_state *state = NULL;
3544         uint8_t additional_flags = 0;
3545
3546         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3547         if (req == NULL) {
3548                 return NULL;
3549         }
3550
3551         SSVAL(state->vwv+0, 0, fnum);
3552         push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
3553                        smb1cli_conn_server_time_zone(cli->conn));
3554         push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
3555                        smb1cli_conn_server_time_zone(cli->conn));
3556         push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
3557                        smb1cli_conn_server_time_zone(cli->conn));
3558
3559         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3560                               7, state->vwv, 0, NULL);
3561         if (tevent_req_nomem(subreq, req)) {
3562                 return tevent_req_post(req, ev);
3563         }
3564         tevent_req_set_callback(subreq, cli_setattrE_done, req);
3565         return req;
3566 }
3567
3568 static void cli_setattrE_done(struct tevent_req *subreq)
3569 {
3570         struct tevent_req *req = tevent_req_callback_data(
3571                 subreq, struct tevent_req);
3572         NTSTATUS status;
3573
3574         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3575         TALLOC_FREE(subreq);
3576         if (tevent_req_nterror(req, status)) {
3577                 return;
3578         }
3579         tevent_req_done(req);
3580 }
3581
3582 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3583 {
3584         return tevent_req_simple_recv_ntstatus(req);
3585 }
3586
3587 NTSTATUS cli_setattrE(struct cli_state *cli,
3588                         uint16_t fnum,
3589                         time_t change_time,
3590                         time_t access_time,
3591                         time_t write_time)
3592 {
3593         TALLOC_CTX *frame = talloc_stackframe();
3594         struct tevent_context *ev = NULL;
3595         struct tevent_req *req = NULL;
3596         NTSTATUS status = NT_STATUS_OK;
3597
3598         if (smbXcli_conn_has_async_calls(cli->conn)) {
3599                 /*
3600                  * Can't use sync call while an async call is in flight
3601                  */
3602                 status = NT_STATUS_INVALID_PARAMETER;
3603                 goto fail;
3604         }
3605
3606         ev = samba_tevent_context_init(frame);
3607         if (ev == NULL) {
3608                 status = NT_STATUS_NO_MEMORY;
3609                 goto fail;
3610         }
3611
3612         req = cli_setattrE_send(frame, ev,
3613                         cli,
3614                         fnum,
3615                         change_time,
3616                         access_time,
3617                         write_time);
3618
3619         if (req == NULL) {
3620                 status = NT_STATUS_NO_MEMORY;
3621                 goto fail;
3622         }
3623
3624         if (!tevent_req_poll(req, ev)) {
3625                 status = map_nt_error_from_unix(errno);
3626                 goto fail;
3627         }
3628
3629         status = cli_setattrE_recv(req);
3630
3631  fail:
3632         TALLOC_FREE(frame);
3633         return status;
3634 }
3635
3636 /****************************************************************************
3637  Do a SMBsetatr call.
3638 ****************************************************************************/
3639
3640 static void cli_setatr_done(struct tevent_req *subreq);
3641
3642 struct cli_setatr_state {
3643         uint16_t vwv[8];
3644 };
3645
3646 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3647                                 struct tevent_context *ev,
3648                                 struct cli_state *cli,
3649                                 const char *fname,
3650                                 uint16_t attr,
3651                                 time_t mtime)
3652 {
3653         struct tevent_req *req = NULL, *subreq = NULL;
3654         struct cli_setatr_state *state = NULL;
3655         uint8_t additional_flags = 0;
3656         uint8_t *bytes = NULL;
3657
3658         req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3659         if (req == NULL) {
3660                 return NULL;
3661         }
3662
3663         SSVAL(state->vwv+0, 0, attr);
3664         push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
3665
3666         bytes = talloc_array(state, uint8_t, 1);
3667         if (tevent_req_nomem(bytes, req)) {
3668                 return tevent_req_post(req, ev);
3669         }
3670         bytes[0] = 4;
3671         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3672                                    strlen(fname)+1, NULL);
3673         if (tevent_req_nomem(bytes, req)) {
3674                 return tevent_req_post(req, ev);
3675         }
3676         bytes = talloc_realloc(state, bytes, uint8_t,
3677                         talloc_get_size(bytes)+1);
3678         if (tevent_req_nomem(bytes, req)) {
3679                 return tevent_req_post(req, ev);
3680         }
3681
3682         bytes[talloc_get_size(bytes)-1] = 4;
3683         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
3684                                    1, NULL);
3685         if (tevent_req_nomem(bytes, req)) {
3686                 return tevent_req_post(req, ev);
3687         }
3688
3689         subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3690                               8, state->vwv, talloc_get_size(bytes), bytes);
3691         if (tevent_req_nomem(subreq, req)) {
3692                 return tevent_req_post(req, ev);
3693         }
3694         tevent_req_set_callback(subreq, cli_setatr_done, req);
3695         return req;
3696 }
3697
3698 static void cli_setatr_done(struct tevent_req *subreq)
3699 {
3700         struct tevent_req *req = tevent_req_callback_data(
3701                 subreq, struct tevent_req);
3702         NTSTATUS status;
3703
3704         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3705         TALLOC_FREE(subreq);
3706         if (tevent_req_nterror(req, status)) {
3707                 return;
3708         }
3709         tevent_req_done(req);
3710 }
3711
3712 NTSTATUS cli_setatr_recv(struct tevent_req *req)
3713 {
3714         return tevent_req_simple_recv_ntstatus(req);
3715 }
3716
3717 NTSTATUS cli_setatr(struct cli_state *cli,
3718                 const char *fname,
3719                 uint16_t attr,
3720                 time_t mtime)
3721 {
3722         TALLOC_CTX *frame = talloc_stackframe();
3723         struct tevent_context *ev = NULL;
3724         struct tevent_req *req = NULL;
3725         NTSTATUS status = NT_STATUS_OK;
3726
3727         if (smbXcli_conn_has_async_calls(cli->conn)) {
3728                 /*
3729                  * Can't use sync call while an async call is in flight
3730                  */
3731                 status = NT_STATUS_INVALID_PARAMETER;
3732                 goto fail;
3733         }
3734
3735         ev = samba_tevent_context_init(frame);
3736         if (ev == NULL) {
3737                 status = NT_STATUS_NO_MEMORY;
3738                 goto fail;
3739         }
3740
3741         req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
3742         if (req == NULL) {
3743                 status = NT_STATUS_NO_MEMORY;
3744                 goto fail;
3745         }
3746
3747         if (!tevent_req_poll(req, ev)) {
3748                 status = map_nt_error_from_unix(errno);
3749                 goto fail;
3750         }
3751
3752         status = cli_setatr_recv(req);
3753
3754  fail:
3755         TALLOC_FREE(frame);
3756         return status;
3757 }
3758
3759 /****************************************************************************
3760  Check for existance of a dir.
3761 ****************************************************************************/
3762
3763 static void cli_chkpath_done(struct tevent_req *subreq);
3764
3765 struct cli_chkpath_state {
3766         int dummy;
3767 };
3768
3769 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
3770                                   struct tevent_context *ev,
3771                                   struct cli_state *cli,
3772                                   const char *fname)
3773 {
3774         struct tevent_req *req = NULL, *subreq = NULL;
3775         struct cli_chkpath_state *state = NULL;
3776         uint8_t additional_flags = 0;
3777         uint8_t *bytes = NULL;
3778
3779         req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
3780         if (req == NULL) {
3781                 return NULL;
3782         }
3783
3784         bytes = talloc_array(state, uint8_t, 1);
3785         if (tevent_req_nomem(bytes, req)) {
3786                 return tevent_req_post(req, ev);
3787         }
3788         bytes[0] = 4;
3789         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3790                                    strlen(fname)+1, NULL);
3791
3792         if (tevent_req_nomem(bytes, req)) {
3793                 return tevent_req_post(req, ev);
3794         }
3795
3796         subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
3797                               0, NULL, talloc_get_size(bytes), bytes);
3798         if (tevent_req_nomem(subreq, req)) {
3799                 return tevent_req_post(req, ev);
3800         }
3801         tevent_req_set_callback(subreq, cli_chkpath_done, req);
3802         return req;
3803 }
3804
3805 static void cli_chkpath_done(struct tevent_req *subreq)
3806 {
3807         struct tevent_req *req = tevent_req_callback_data(
3808                 subreq, struct tevent_req);
3809         NTSTATUS status;
3810
3811         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3812         TALLOC_FREE(subreq);
3813         if (tevent_req_nterror(req, status)) {
3814                 return;
3815         }
3816         tevent_req_done(req);
3817 }
3818
3819 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
3820 {
3821         return tevent_req_simple_recv_ntstatus(req);
3822 }
3823
3824 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
3825 {
3826         TALLOC_CTX *frame = talloc_stackframe();
3827         struct tevent_context *ev = NULL;
3828         struct tevent_req *req = NULL;
3829         char *path2 = NULL;
3830         NTSTATUS status = NT_STATUS_OK;
3831
3832         if (smbXcli_conn_has_async_calls(cli->conn)) {
3833                 /*
3834                  * Can't use sync call while an async call is in flight
3835                  */
3836                 status = NT_STATUS_INVALID_PARAMETER;
3837                 goto fail;
3838         }
3839
3840         path2 = talloc_strdup(frame, path);
3841         if (!path2) {
3842                 status = NT_STATUS_NO_MEMORY;
3843                 goto fail;
3844         }
3845         trim_char(path2,'\0','\\');
3846         if (!*path2) {
3847                 path2 = talloc_strdup(frame, "\\");
3848                 if (!path2) {
3849                         status = NT_STATUS_NO_MEMORY;
3850                         goto fail;
3851                 }
3852         }
3853
3854         ev = samba_tevent_context_init(frame);
3855         if (ev == NULL) {
3856                 status = NT_STATUS_NO_MEMORY;
3857                 goto fail;
3858         }
3859
3860         req = cli_chkpath_send(frame, ev, cli, path2);
3861         if (req == NULL) {
3862                 status = NT_STATUS_NO_MEMORY;
3863                 goto fail;
3864         }
3865
3866         if (!tevent_req_poll(req, ev)) {
3867                 status = map_nt_error_from_unix(errno);
3868                 goto fail;
3869         }
3870
3871         status = cli_chkpath_recv(req);
3872
3873  fail:
3874         TALLOC_FREE(frame);
3875         return status;
3876 }
3877
3878 /****************************************************************************
3879  Query disk space.
3880 ****************************************************************************/
3881
3882 static void cli_dskattr_done(struct tevent_req *subreq);
3883
3884 struct cli_dskattr_state {
3885         int bsize;
3886         int total;
3887         int avail;
3888 };
3889
3890 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
3891                                   struct tevent_context *ev,
3892                                   struct cli_state *cli)
3893 {
3894         struct tevent_req *req = NULL, *subreq = NULL;
3895         struct cli_dskattr_state *state = NULL;
3896         uint8_t additional_flags = 0;
3897
3898         req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
3899         if (req == NULL) {
3900                 return NULL;
3901         }
3902
3903         subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
3904                               0, NULL, 0, NULL);
3905         if (tevent_req_nomem(subreq, req)) {
3906                 return tevent_req_post(req, ev);
3907         }
3908         tevent_req_set_callback(subreq, cli_dskattr_done, req);
3909         return req;
3910 }
3911
3912 static void cli_dskattr_done(struct tevent_req *subreq)
3913 {
3914         struct tevent_req *req = tevent_req_callback_data(
3915                 subreq, struct tevent_req);
3916         struct cli_dskattr_state *state = tevent_req_data(
3917                 req, struct cli_dskattr_state);
3918         uint8_t wct;
3919         uint16_t *vwv = NULL;
3920         NTSTATUS status;
3921
3922         status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
3923                               NULL);
3924         TALLOC_FREE(subreq);
3925         if (tevent_req_nterror(req, status)) {
3926                 return;
3927         }
3928         state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
3929         state->total = SVAL(vwv+0, 0);
3930         state->avail = SVAL(vwv+3, 0);
3931         tevent_req_done(req);
3932 }
3933
3934 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
3935 {
3936         struct cli_dskattr_state *state = tevent_req_data(
3937                                 req, struct cli_dskattr_state);
3938         NTSTATUS status;
3939
3940         if (tevent_req_is_nterror(req, &status)) {
3941                 return status;
3942         }
3943         *bsize = state->bsize;
3944         *total = state->total;
3945         *avail = state->avail;
3946         return NT_STATUS_OK;
3947 }
3948
3949 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3950 {
3951         TALLOC_CTX *frame = talloc_stackframe();
3952         struct tevent_context *ev = NULL;
3953         struct tevent_req *req = NULL;
3954         NTSTATUS status = NT_STATUS_OK;
3955
3956         if (smbXcli_conn_has_async_calls(cli->conn)) {
3957                 /*
3958                  * Can't use sync call while an async call is in flight
3959                  */
3960                 status = NT_STATUS_INVALID_PARAMETER;
3961                 goto fail;
3962         }
3963
3964         ev = samba_tevent_context_init(frame);
3965         if (ev == NULL) {
3966                 status = NT_STATUS_NO_MEMORY;
3967                 goto fail;
3968         }
3969
3970         req = cli_dskattr_send(frame, ev, cli);
3971         if (req == NULL) {
3972                 status = NT_STATUS_NO_MEMORY;
3973                 goto fail;
3974         }
3975
3976         if (!tevent_req_poll(req, ev)) {
3977                 status = map_nt_error_from_unix(errno);
3978                 goto fail;
3979         }
3980
3981         status = cli_dskattr_recv(req, bsize, total, avail);
3982
3983  fail:
3984         TALLOC_FREE(frame);
3985         return status;
3986 }
3987
3988 /****************************************************************************
3989  Create and open a temporary file.
3990 ****************************************************************************/
3991
3992 static void cli_ctemp_done(struct tevent_req *subreq);
3993
3994 struct ctemp_state {
3995         uint16_t vwv[3];
3996         char *ret_path;
3997         uint16_t fnum;
3998 };
3999
4000 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4001                                 struct tevent_context *ev,
4002                                 struct cli_state *cli,
4003                                 const char *path)
4004 {
4005         struct tevent_req *req = NULL, *subreq = NULL;
4006         struct ctemp_state *state = NULL;
4007         uint8_t additional_flags = 0;
4008         uint8_t *bytes = NULL;
4009
4010         req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4011         if (req == NULL) {
4012                 return NULL;
4013         }
4014
4015         SSVAL(state->vwv,0,0);
4016         SIVALS(state->vwv+1,0,-1);
4017
4018         bytes = talloc_array(state, uint8_t, 1);
4019         if (tevent_req_nomem(bytes, req)) {
4020                 return tevent_req_post(req, ev);
4021         }
4022         bytes[0] = 4;
4023         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), path,
4024                                    strlen(path)+1, NULL);
4025         if (tevent_req_nomem(bytes, req)) {
4026                 return tevent_req_post(req, ev);
4027         }
4028
4029         subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4030                               3, state->vwv, talloc_get_size(bytes), bytes);
4031         if (tevent_req_nomem(subreq, req)) {
4032                 return tevent_req_post(req, ev);
4033         }
4034         tevent_req_set_callback(subreq, cli_ctemp_done, req);
4035         return req;
4036 }
4037
4038 static void cli_ctemp_done(struct tevent_req *subreq)
4039 {
4040         struct tevent_req *req = tevent_req_callback_data(
4041                                 subreq, struct tevent_req);
4042         struct ctemp_state *state = tevent_req_data(
4043                                 req, struct ctemp_state);
4044         NTSTATUS status;
4045         uint8_t wcnt;
4046         uint16_t *vwv;
4047         uint32_t num_bytes = 0;
4048         uint8_t *bytes = NULL;
4049
4050         status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
4051                               &num_bytes, &bytes);
4052         TALLOC_FREE(subreq);
4053         if (tevent_req_nterror(req, status)) {
4054                 return;
4055         }
4056
4057         state->fnum = SVAL(vwv+0, 0);
4058
4059         /* From W2K3, the result is just the ASCII name */
4060         if (num_bytes < 2) {
4061                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
4062                 return;
4063         }
4064
4065         if (pull_string_talloc(state,
4066                         NULL,
4067                         0,
4068                         &state->ret_path,
4069                         bytes,
4070                         num_bytes,
4071                         STR_ASCII) == 0) {
4072                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4073                 return;
4074         }
4075         tevent_req_done(req);
4076 }
4077
4078 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
4079                         TALLOC_CTX *ctx,
4080                         uint16_t *pfnum,
4081                         char **outfile)
4082 {
4083         struct ctemp_state *state = tevent_req_data(req,
4084                         struct ctemp_state);
4085         NTSTATUS status;
4086
4087         if (tevent_req_is_nterror(req, &status)) {
4088                 return status;
4089         }
4090         *pfnum = state->fnum;
4091         *outfile = talloc_strdup(ctx, state->ret_path);
4092         if (!*outfile) {
4093                 return NT_STATUS_NO_MEMORY;
4094         }
4095         return NT_STATUS_OK;
4096 }
4097
4098 NTSTATUS cli_ctemp(struct cli_state *cli,
4099                         TALLOC_CTX *ctx,
4100                         const char *path,
4101                         uint16_t *pfnum,
4102                         char **out_path)
4103 {
4104         TALLOC_CTX *frame = talloc_stackframe();
4105         struct tevent_context *ev;
4106         struct tevent_req *req;
4107         NTSTATUS status = NT_STATUS_OK;
4108
4109         if (smbXcli_conn_has_async_calls(cli->conn)) {
4110                 /*
4111                  * Can't use sync call while an async call is in flight
4112                  */
4113                 status = NT_STATUS_INVALID_PARAMETER;
4114                 goto fail;
4115         }
4116
4117         ev = samba_tevent_context_init(frame);
4118         if (ev == NULL) {
4119                 status = NT_STATUS_NO_MEMORY;
4120                 goto fail;
4121         }
4122
4123         req = cli_ctemp_send(frame, ev, cli, path);
4124         if (req == NULL) {
4125                 status = NT_STATUS_NO_MEMORY;
4126                 goto fail;
4127         }
4128
4129         if (!tevent_req_poll(req, ev)) {
4130                 status = map_nt_error_from_unix(errno);
4131                 goto fail;
4132         }
4133
4134         status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4135
4136  fail:
4137         TALLOC_FREE(frame);
4138         return status;
4139 }
4140
4141 /*
4142    send a raw ioctl - used by the torture code
4143 */
4144 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4145 {
4146         uint16_t vwv[3];
4147         NTSTATUS status;
4148
4149         SSVAL(vwv+0, 0, fnum);
4150         SSVAL(vwv+1, 0, code>>16);
4151         SSVAL(vwv+2, 0, (code&0xFFFF));
4152
4153         status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4154                          NULL, 0, NULL, NULL, NULL, NULL);
4155         if (!NT_STATUS_IS_OK(status)) {
4156                 return status;
4157         }
4158         *blob = data_blob_null;
4159         return NT_STATUS_OK;
4160 }
4161
4162 /*********************************************************
4163  Set an extended attribute utility fn.
4164 *********************************************************/
4165
4166 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
4167                            uint8_t *param, unsigned int param_len,
4168                            const char *ea_name,
4169                            const char *ea_val, size_t ea_len)
4170 {
4171         uint16_t setup[1];
4172         unsigned int data_len = 0;
4173         uint8_t *data = NULL;
4174         char *p;
4175         size_t ea_namelen = strlen(ea_name);
4176         NTSTATUS status;
4177
4178         SSVAL(setup, 0, setup_val);
4179
4180         if (ea_namelen == 0 && ea_len == 0) {
4181                 data_len = 4;
4182                 data = talloc_array(talloc_tos(),
4183                                 uint8_t,
4184                                 data_len);
4185                 if (!data) {
4186                         return NT_STATUS_NO_MEMORY;
4187                 }
4188                 p = (char *)data;
4189                 SIVAL(p,0,data_len);
4190         } else {
4191                 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4192                 data = talloc_array(talloc_tos(),
4193                                 uint8_t,
4194                                 data_len);
4195                 if (!data) {
4196                         return NT_STATUS_NO_MEMORY;
4197                 }
4198                 p = (char *)data;
4199                 SIVAL(p,0,data_len);
4200                 p += 4;
4201                 SCVAL(p, 0, 0); /* EA flags. */
4202                 SCVAL(p, 1, ea_namelen);
4203                 SSVAL(p, 2, ea_len);
4204                 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4205                 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4206         }
4207
4208         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
4209                            setup, 1, 0,
4210                            param, param_len, 2,
4211                            data,  data_len, CLI_BUFFER_SIZE,
4212                            NULL,
4213                            NULL, 0, NULL, /* rsetup */
4214                            NULL, 0, NULL, /* rparam */
4215                            NULL, 0, NULL); /* rdata */
4216         talloc_free(data);
4217         return status;
4218 }
4219
4220 /*********************************************************
4221  Set an extended attribute on a pathname.
4222 *********************************************************/
4223
4224 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
4225                          const char *ea_name, const char *ea_val,
4226                          size_t ea_len)
4227 {
4228         unsigned int param_len = 0;
4229         uint8_t *param;
4230         NTSTATUS status;
4231         TALLOC_CTX *frame = talloc_stackframe();
4232
4233         param = talloc_array(talloc_tos(), uint8_t, 6);
4234         if (!param) {
4235                 return NT_STATUS_NO_MEMORY;
4236         }
4237         SSVAL(param,0,SMB_INFO_SET_EA);
4238         SSVAL(param,2,0);
4239         SSVAL(param,4,0);
4240
4241         param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
4242                                       path, strlen(path)+1,
4243                                       NULL);
4244         param_len = talloc_get_size(param);
4245
4246         status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
4247                             ea_name, ea_val, ea_len);
4248         talloc_free(frame);
4249         return status;
4250 }
4251
4252 /*********************************************************
4253  Set an extended attribute on an fnum.
4254 *********************************************************/
4255
4256 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
4257                          const char *ea_name, const char *ea_val,
4258                          size_t ea_len)
4259 {
4260         uint8_t param[6];
4261
4262         memset(param, 0, 6);
4263         SSVAL(param,0,fnum);
4264         SSVAL(param,2,SMB_INFO_SET_EA);
4265
4266         return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
4267                           ea_name, ea_val, ea_len);
4268 }
4269
4270 /*********************************************************
4271  Get an extended attribute list utility fn.
4272 *********************************************************/
4273
4274 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4275                           size_t rdata_len,
4276                           size_t *pnum_eas, struct ea_struct **pea_list)
4277 {
4278         struct ea_struct *ea_list = NULL;
4279         size_t num_eas;
4280         size_t ea_size;
4281         const uint8_t *p;
4282
4283         if (rdata_len < 4) {
4284                 return false;
4285         }
4286
4287         ea_size = (size_t)IVAL(rdata,0);
4288         if (ea_size > rdata_len) {
4289                 return false;
4290         }
4291
4292         if (ea_size == 0) {
4293                 /* No EA's present. */
4294                 *pnum_eas = 0;
4295                 *pea_list = NULL;
4296                 return true;
4297         }
4298
4299         p = rdata + 4;
4300         ea_size -= 4;
4301
4302         /* Validate the EA list and count it. */
4303         for (num_eas = 0; ea_size >= 4; num_eas++) {
4304                 unsigned int ea_namelen = CVAL(p,1);
4305                 unsigned int ea_valuelen = SVAL(p,2);
4306                 if (ea_namelen == 0) {
4307                         return false;
4308                 }
4309                 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4310                         return false;
4311                 }
4312                 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4313                 p += 4 + ea_namelen + 1 + ea_valuelen;
4314         }
4315
4316         if (num_eas == 0) {
4317                 *pnum_eas = 0;
4318                 *pea_list = NULL;
4319                 return true;
4320         }
4321
4322         *pnum_eas = num_eas;
4323         if (!pea_list) {
4324                 /* Caller only wants number of EA's. */
4325                 return true;
4326         }
4327
4328         ea_list = talloc_array(ctx, struct ea_struct, num_eas);
4329         if (!ea_list) {
4330                 return false;
4331         }
4332
4333         ea_size = (size_t)IVAL(rdata,0);
4334         p = rdata + 4;
4335
4336         for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4337                 struct ea_struct *ea = &ea_list[num_eas];
4338                 fstring unix_ea_name;
4339                 unsigned int ea_namelen = CVAL(p,1);
4340                 unsigned int ea_valuelen = SVAL(p,2);
4341
4342                 ea->flags = CVAL(p,0);
4343                 unix_ea_name[0] = '\0';
4344                 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
4345                 ea->name = talloc_strdup(ea_list, unix_ea_name);
4346                 if (!ea->name) {
4347                         goto fail;
4348                 }
4349                 /* Ensure the value is null terminated (in case it's a string). */
4350                 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4351                 if (!ea->value.data) {
4352                         goto fail;
4353                 }
4354                 if (ea_valuelen) {
4355                         memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4356                 }
4357                 ea->value.data[ea_valuelen] = 0;
4358                 ea->value.length--;
4359                 p += 4 + ea_namelen + 1 + ea_valuelen;
4360         }
4361
4362         *pea_list = ea_list;
4363         return true;
4364
4365 fail:
4366         TALLOC_FREE(ea_list);
4367         return false;
4368 }
4369
4370 /*********************************************************
4371  Get an extended attribute list from a pathname.
4372 *********************************************************/
4373
4374 struct cli_get_ea_list_path_state {
4375         uint32_t num_data;
4376         uint8_t *data;
4377 };
4378
4379 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4380
4381 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4382                                              struct tevent_context *ev,
4383                                              struct cli_state *cli,
4384                                              const char *fname)
4385 {
4386         struct tevent_req *req, *subreq;
4387         struct cli_get_ea_list_path_state *state;
4388
4389         req = tevent_req_create(mem_ctx, &state,
4390                                 struct cli_get_ea_list_path_state);
4391         if (req == NULL) {
4392                 return NULL;
4393         }
4394         subreq = cli_qpathinfo_send(state, ev, cli, fname,
4395                                     SMB_INFO_QUERY_ALL_EAS, 4,
4396                                     CLI_BUFFER_SIZE);
4397         if (tevent_req_nomem(subreq, req)) {
4398                 return tevent_req_post(req, ev);
4399         }
4400         tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4401         return req;
4402 }
4403
4404 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4405 {
4406         struct tevent_req *req = tevent_req_callback_data(
4407                                 subreq, struct tevent_req);
4408         struct cli_get_ea_list_path_state *state = tevent_req_data(
4409                 req, struct cli_get_ea_list_path_state);
4410         NTSTATUS status;
4411
4412         status = cli_qpathinfo_recv(subreq, state, &state->data,
4413                                     &state->num_data);
4414         TALLOC_FREE(subreq);
4415         if (tevent_req_nterror(req, status)) {
4416                 return;
4417         }
4418         tevent_req_done(req);
4419 }
4420
4421 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4422                                    size_t *pnum_eas, struct ea_struct **peas)
4423 {
4424         struct cli_get_ea_list_path_state *state = tevent_req_data(
4425                 req, struct cli_get_ea_list_path_state);
4426         NTSTATUS status;
4427
4428         if (tevent_req_is_nterror(req, &status)) {
4429                 return status;
4430         }
4431         if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4432                            pnum_eas, peas)) {
4433                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4434         }
4435         return NT_STATUS_OK;
4436 }
4437
4438 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
4439                 TALLOC_CTX *ctx,
4440                 size_t *pnum_eas,
4441                 struct ea_struct **pea_list)
4442 {
4443         TALLOC_CTX *frame = talloc_stackframe();
4444         struct tevent_context *ev = NULL;
4445         struct tevent_req *req = NULL;
4446         NTSTATUS status = NT_STATUS_NO_MEMORY;
4447
4448         if (smbXcli_conn_has_async_calls(cli->conn)) {
4449                 /*
4450                  * Can't use sync call while an async call is in flight
4451                  */
4452                 status = NT_STATUS_INVALID_PARAMETER;
4453                 goto fail;
4454         }
4455         ev = samba_tevent_context_init(frame);
4456         if (ev == NULL) {
4457                 goto fail;
4458         }
4459         req = cli_get_ea_list_path_send(frame, ev, cli, path);
4460         if (req == NULL) {
4461                 goto fail;
4462         }
4463         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4464                 goto fail;
4465         }
4466         status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
4467  fail:
4468         TALLOC_FREE(frame);
4469         return status;
4470 }
4471
4472 /****************************************************************************
4473  Convert open "flags" arg to uint32_t on wire.
4474 ****************************************************************************/
4475
4476 static uint32_t open_flags_to_wire(int flags)
4477 {
4478         int open_mode = flags & O_ACCMODE;
4479         uint32_t ret = 0;
4480
4481         switch (open_mode) {
4482                 case O_WRONLY:
4483                         ret |= SMB_O_WRONLY;
4484                         break;
4485                 case O_RDWR:
4486                         ret |= SMB_O_RDWR;
4487                         break;
4488                 default:
4489                 case O_RDONLY:
4490                         ret |= SMB_O_RDONLY;
4491                         break;
4492         }
4493
4494         if (flags & O_CREAT) {
4495                 ret |= SMB_O_CREAT;
4496         }
4497         if (flags & O_EXCL) {
4498                 ret |= SMB_O_EXCL;
4499         }
4500         if (flags & O_TRUNC) {
4501                 ret |= SMB_O_TRUNC;
4502         }
4503 #if defined(O_SYNC)
4504         if (flags & O_SYNC) {
4505                 ret |= SMB_O_SYNC;
4506         }
4507 #endif /* O_SYNC */
4508         if (flags & O_APPEND) {
4509                 ret |= SMB_O_APPEND;
4510         }
4511 #if defined(O_DIRECT)
4512         if (flags & O_DIRECT) {
4513                 ret |= SMB_O_DIRECT;
4514         }
4515 #endif
4516 #if defined(O_DIRECTORY)
4517         if (flags & O_DIRECTORY) {
4518                 ret |= SMB_O_DIRECTORY;
4519         }
4520 #endif
4521         return ret;
4522 }
4523
4524 /****************************************************************************
4525  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4526 ****************************************************************************/
4527
4528 struct posix_open_state {
4529         uint16_t setup;
4530         uint8_t *param;
4531         uint8_t data[18];
4532         uint16_t fnum; /* Out */
4533 };
4534
4535 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4536 {
4537         struct tevent_req *req = tevent_req_callback_data(
4538                                 subreq, struct tevent_req);
4539         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4540         NTSTATUS status;
4541         uint8_t *data;
4542         uint32_t num_data;
4543
4544         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
4545                                 NULL, 0, NULL, &data, 12, &num_data);
4546         TALLOC_FREE(subreq);
4547         if (tevent_req_nterror(req, status)) {
4548                 return;
4549         }
4550         state->fnum = SVAL(data,2);
4551         tevent_req_done(req);
4552 }
4553
4554 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4555                                         struct tevent_context *ev,
4556                                         struct cli_state *cli,
4557                                         const char *fname,
4558                                         int flags,
4559                                         mode_t mode,
4560                                         bool is_dir)
4561 {
4562         struct tevent_req *req = NULL, *subreq = NULL;
4563         struct posix_open_state *state = NULL;
4564         uint32_t wire_flags = open_flags_to_wire(flags);
4565
4566         req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4567         if (req == NULL) {
4568                 return NULL;
4569         }
4570
4571         /* Setup setup word. */
4572         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4573
4574         /* Setup param array. */
4575         state->param = talloc_array(state, uint8_t, 6);
4576         if (tevent_req_nomem(state->param, req)) {
4577                 return tevent_req_post(req, ev);
4578         }
4579         memset(state->param, '\0', 6);
4580         SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4581
4582         state->param = trans2_bytes_push_str(state->param, smbXcli_conn_use_unicode(cli->conn), fname,
4583                                    strlen(fname)+1, NULL);
4584
4585         if (tevent_req_nomem(state->param, req)) {
4586                 return tevent_req_post(req, ev);
4587         }
4588
4589         /* Setup data words. */
4590         if (is_dir) {
4591                 wire_flags |= SMB_O_DIRECTORY;
4592         }
4593
4594         SIVAL(state->data,0,0); /* No oplock. */
4595         SIVAL(state->data,4,wire_flags);
4596         SIVAL(state->data,8,unix_perms_to_wire(mode));
4597         SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
4598         SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
4599
4600         subreq = cli_trans_send(state,                  /* mem ctx. */
4601                                 ev,                     /* event ctx. */
4602                                 cli,                    /* cli_state. */
4603                                 SMBtrans2,              /* cmd. */
4604                                 NULL,                   /* pipe name. */
4605                                 -1,                     /* fid. */
4606                                 0,                      /* function. */
4607                                 0,                      /* flags. */
4608                                 &state->setup,          /* setup. */
4609                                 1,                      /* num setup uint16_t words. */
4610                                 0,                      /* max returned setup. */
4611                                 state->param,           /* param. */
4612                                 talloc_get_size(state->param),/* num param. */
4613                                 2,                      /* max returned param. */
4614                                 state->data,            /* data. */
4615                                 18,                     /* num data. */
4616                                 12);                    /* max returned data. */
4617
4618         if (tevent_req_nomem(subreq, req)) {
4619                 return tevent_req_post(req, ev);
4620         }
4621         tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
4622         return req;
4623 }
4624
4625 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
4626                                         struct tevent_context *ev,
4627                                         struct cli_state *cli,
4628                                         const char *fname,
4629                                         int flags,
4630                                         mode_t mode)
4631 {
4632         return cli_posix_open_internal_send(mem_ctx, ev,
4633                                 cli, fname, flags, mode, false);
4634 }
4635
4636 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
4637 {
4638         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4639         NTSTATUS status;
4640
4641         if (tevent_req_is_nterror(req, &status)) {
4642                 return status;
4643         }
4644         *pfnum = state->fnum;
4645         return NT_STATUS_OK;
4646 }
4647
4648 /****************************************************************************
4649  Open - POSIX semantics. Doesn't request oplock.
4650 ****************************************************************************/
4651
4652 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
4653                         int flags, mode_t mode, uint16_t *pfnum)
4654 {
4655
4656         TALLOC_CTX *frame = talloc_stackframe();
4657         struct tevent_context *ev = NULL;
4658         struct tevent_req *req = NULL;
4659         NTSTATUS status = NT_STATUS_OK;
4660
4661         if (smbXcli_conn_has_async_calls(cli->conn)) {
4662                 /*
4663                  * Can't use sync call while an async call is in flight
4664                  */
4665                 status = NT_STATUS_INVALID_PARAMETER;
4666                 goto fail;
4667         }
4668
4669         ev = samba_tevent_context_init(frame);
4670         if (ev == NULL) {
4671                 status = NT_STATUS_NO_MEMORY;
4672                 goto fail;
4673         }
4674
4675         req = cli_posix_open_send(frame,
4676                                 ev,
4677                                 cli,
4678                                 fname,
4679                                 flags,
4680                                 mode);
4681         if (req == NULL) {
4682                 status = NT_STATUS_NO_MEMORY;
4683                 goto fail;
4684         }
4685
4686         if (!tevent_req_poll(req, ev)) {
4687                 status = map_nt_error_from_unix(errno);
4688                 goto fail;
4689         }
4690
4691         status = cli_posix_open_recv(req, pfnum);
4692
4693  fail:
4694         TALLOC_FREE(frame);
4695         return status;
4696 }
4697
4698 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
4699                                         struct tevent_context *ev,
4700                                         struct cli_state *cli,
4701                                         const char *fname,
4702                                         mode_t mode)
4703 {
4704         return cli_posix_open_internal_send(mem_ctx, ev,
4705                                 cli, fname, O_CREAT, mode, true);
4706 }
4707
4708 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
4709 {
4710         return tevent_req_simple_recv_ntstatus(req);
4711 }
4712
4713 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
4714 {
4715         TALLOC_CTX *frame = talloc_stackframe();
4716         struct tevent_context *ev = NULL;
4717         struct tevent_req *req = NULL;
4718         NTSTATUS status = NT_STATUS_OK;
4719
4720         if (smbXcli_conn_has_async_calls(cli->conn)) {
4721                 /*
4722                  * Can't use sync call while an async call is in flight
4723                  */
4724                 status = NT_STATUS_INVALID_PARAMETER;
4725                 goto fail;
4726         }
4727
4728         ev = samba_tevent_context_init(frame);
4729         if (ev == NULL) {
4730                 status = NT_STATUS_NO_MEMORY;
4731                 goto fail;
4732         }
4733
4734         req = cli_posix_mkdir_send(frame,
4735                                 ev,
4736                                 cli,
4737                                 fname,
4738                                 mode);
4739         if (req == NULL) {
4740                 status = NT_STATUS_NO_MEMORY;
4741                 goto fail;
4742         }
4743
4744         if (!tevent_req_poll(req, ev)) {
4745                 status = map_nt_error_from_unix(errno);
4746                 goto fail;
4747         }
4748
4749         status = cli_posix_mkdir_recv(req);
4750
4751  fail:
4752         TALLOC_FREE(frame);
4753         return status;
4754 }
4755
4756 /****************************************************************************
4757  unlink or rmdir - POSIX semantics.
4758 ****************************************************************************/
4759
4760 struct cli_posix_unlink_internal_state {
4761         uint8_t data[2];
4762 };
4763
4764 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
4765
4766 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
4767                                         struct tevent_context *ev,
4768                                         struct cli_state *cli,
4769                                         const char *fname,
4770                                         uint16_t level)
4771 {
4772         struct tevent_req *req = NULL, *subreq = NULL;
4773         struct cli_posix_unlink_internal_state *state = NULL;
4774
4775         req = tevent_req_create(mem_ctx, &state,
4776                                 struct cli_posix_unlink_internal_state);
4777         if (req == NULL) {
4778                 return NULL;
4779         }
4780
4781         /* Setup data word. */
4782         SSVAL(state->data, 0, level);
4783
4784         subreq = cli_setpathinfo_send(state, ev, cli,
4785                                       SMB_POSIX_PATH_UNLINK,
4786                                       fname,
4787                                       state->data, sizeof(state->data));
4788         if (tevent_req_nomem(subreq, req)) {
4789                 return tevent_req_post(req, ev);
4790         }
4791         tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
4792         return req;
4793 }
4794
4795 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
4796 {
4797         NTSTATUS status = cli_setpathinfo_recv(subreq);
4798         tevent_req_simple_finish_ntstatus(subreq, status);
4799 }
4800
4801 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
4802                                         struct tevent_context *ev,
4803                                         struct cli_state *cli,
4804                                         const char *fname)
4805 {
4806         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
4807                                               SMB_POSIX_UNLINK_FILE_TARGET);
4808 }
4809
4810 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
4811 {
4812         return tevent_req_simple_recv_ntstatus(req);
4813 }
4814
4815 /****************************************************************************
4816  unlink - POSIX semantics.
4817 ****************************************************************************/
4818
4819 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
4820 {
4821         TALLOC_CTX *frame = talloc_stackframe();
4822         struct tevent_context *ev = NULL;
4823         struct tevent_req *req = NULL;
4824         NTSTATUS status = NT_STATUS_OK;
4825
4826         if (smbXcli_conn_has_async_calls(cli->conn)) {
4827                 /*
4828                  * Can't use sync call while an async call is in flight
4829                  */
4830                 status = NT_STATUS_INVALID_PARAMETER;
4831                 goto fail;
4832         }
4833
4834         ev = samba_tevent_context_init(frame);
4835         if (ev == NULL) {
4836                 status = NT_STATUS_NO_MEMORY;
4837                 goto fail;
4838         }
4839
4840         req = cli_posix_unlink_send(frame,
4841                                 ev,
4842                                 cli,
4843                                 fname);
4844         if (req == NULL) {
4845                 status = NT_STATUS_NO_MEMORY;
4846                 goto fail;
4847         }
4848
4849         if (!tevent_req_poll(req, ev)) {
4850                 status = map_nt_error_from_unix(errno);
4851                 goto fail;
4852         }
4853
4854         status = cli_posix_unlink_recv(req);
4855
4856  fail:
4857         TALLOC_FREE(frame);
4858         return status;
4859 }
4860
4861 /****************************************************************************
4862  rmdir - POSIX semantics.
4863 ****************************************************************************/
4864
4865 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
4866                                         struct tevent_context *ev,
4867                                         struct cli_state *cli,
4868                                         const char *fname)
4869 {
4870         return cli_posix_unlink_internal_send(
4871                 mem_ctx, ev, cli, fname,
4872                 SMB_POSIX_UNLINK_DIRECTORY_TARGET);
4873 }
4874
4875 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
4876 {
4877         return tevent_req_simple_recv_ntstatus(req);
4878 }
4879
4880 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
4881 {
4882         TALLOC_CTX *frame = talloc_stackframe();
4883         struct tevent_context *ev = NULL;
4884         struct tevent_req *req = NULL;
4885         NTSTATUS status = NT_STATUS_OK;
4886
4887         if (smbXcli_conn_has_async_calls(cli->conn)) {
4888                 /*
4889                  * Can't use sync call while an async call is in flight
4890                  */
4891                 status = NT_STATUS_INVALID_PARAMETER;
4892                 goto fail;
4893         }
4894
4895         ev = samba_tevent_context_init(frame);
4896         if (ev == NULL) {
4897                 status = NT_STATUS_NO_MEMORY;
4898                 goto fail;
4899         }
4900
4901         req = cli_posix_rmdir_send(frame,
4902                                 ev,
4903                                 cli,
4904                                 fname);
4905         if (req == NULL) {
4906                 status = NT_STATUS_NO_MEMORY;
4907                 goto fail;
4908         }
4909
4910         if (!tevent_req_poll(req, ev)) {
4911                 status = map_nt_error_from_unix(errno);
4912                 goto fail;
4913         }
4914
4915         status = cli_posix_rmdir_recv(req, frame);
4916
4917  fail:
4918         TALLOC_FREE(frame);
4919         return status;
4920 }
4921
4922 /****************************************************************************
4923  filechangenotify
4924 ****************************************************************************/
4925
4926 struct cli_notify_state {
4927         uint8_t setup[8];
4928         uint32_t num_changes;
4929         struct notify_change *changes;
4930 };
4931
4932 static void cli_notify_done(struct tevent_req *subreq);
4933
4934 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
4935                                    struct tevent_context *ev,
4936                                    struct cli_state *cli, uint16_t fnum,
4937                                    uint32_t buffer_size,
4938                                    uint32_t completion_filter, bool recursive)
4939 {
4940         struct tevent_req *req, *subreq;
4941         struct cli_notify_state *state;
4942         unsigned old_timeout;
4943
4944         req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
4945         if (req == NULL) {
4946                 return NULL;
4947         }
4948
4949         SIVAL(state->setup, 0, completion_filter);
4950         SSVAL(state->setup, 4, fnum);
4951         SSVAL(state->setup, 6, recursive);
4952
4953         /*
4954          * Notifies should not time out
4955          */
4956         old_timeout = cli_set_timeout(cli, 0);
4957
4958         subreq = cli_trans_send(
4959                 state,                  /* mem ctx. */
4960                 ev,                     /* event ctx. */
4961                 cli,                    /* cli_state. */
4962                 SMBnttrans,             /* cmd. */
4963                 NULL,                   /* pipe name. */
4964                 -1,                     /* fid. */
4965                 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
4966                 0,                      /* flags. */
4967                 (uint16_t *)state->setup, /* setup. */
4968                 4,                      /* num setup uint16_t words. */
4969                 0,                      /* max returned setup. */
4970                 NULL,                   /* param. */
4971                 0,                      /* num param. */
4972                 buffer_size,            /* max returned param. */
4973                 NULL,                   /* data. */
4974                 0,                      /* num data. */
4975                 0);                     /* max returned data. */
4976
4977         cli_set_timeout(cli, old_timeout);
4978
4979         if (tevent_req_nomem(subreq, req)) {
4980                 return tevent_req_post(req, ev);
4981         }
4982         tevent_req_set_callback(subreq, cli_notify_done, req);
4983         return req;
4984 }
4985
4986 static void cli_notify_done(struct tevent_req *subreq)
4987 {
4988         struct tevent_req *req = tevent_req_callback_data(
4989                 subreq, struct tevent_req);
4990         struct cli_notify_state *state = tevent_req_data(
4991                 req, struct cli_notify_state);
4992         NTSTATUS status;
4993         uint8_t *params;
4994         uint32_t i, ofs, num_params;
4995         uint16_t flags2;
4996
4997         status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
4998                                 &params, 0, &num_params, NULL, 0, NULL);
4999         TALLOC_FREE(subreq);
5000         if (tevent_req_nterror(req, status)) {
5001                 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
5002                 return;
5003         }
5004
5005         state->num_changes = 0;
5006         ofs = 0;
5007
5008         while (num_params - ofs > 12) {
5009                 uint32_t next = IVAL(params, ofs);
5010                 state->num_changes += 1;
5011
5012                 if ((next == 0) || (ofs+next >= num_params)) {
5013                         break;
5014                 }
5015                 ofs += next;
5016         }
5017
5018         state->changes = talloc_array(state, struct notify_change,
5019                                       state->num_changes);
5020         if (tevent_req_nomem(state->changes, req)) {
5021                 TALLOC_FREE(params);
5022                 return;
5023         }
5024
5025         ofs = 0;
5026
5027         for (i=0; i<state->num_changes; i++) {
5028                 uint32_t next = IVAL(params, ofs);
5029                 uint32_t len = IVAL(params, ofs+8);
5030                 ssize_t ret;
5031                 char *name;
5032
5033                 if (trans_oob(num_params, ofs + 12, len)) {
5034                         TALLOC_FREE(params);
5035                         tevent_req_nterror(
5036                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5037                         return;
5038                 }
5039
5040                 state->changes[i].action = IVAL(params, ofs+4);
5041                 ret = clistr_pull_talloc(state->changes, (char *)params, flags2,
5042                                          &name, params+ofs+12, len,
5043                                          STR_TERMINATE|STR_UNICODE);
5044                 if (ret == -1) {
5045                         TALLOC_FREE(params);
5046                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5047                         return;
5048                 }
5049                 state->changes[i].name = name;
5050                 ofs += next;
5051         }
5052
5053         TALLOC_FREE(params);
5054         tevent_req_done(req);
5055 }
5056
5057 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5058                          uint32_t *pnum_changes,
5059                          struct notify_change **pchanges)
5060 {
5061         struct cli_notify_state *state = tevent_req_data(
5062                 req, struct cli_notify_state);
5063         NTSTATUS status;
5064
5065         if (tevent_req_is_nterror(req, &status)) {
5066                 return status;
5067         }
5068
5069         *pnum_changes = state->num_changes;
5070         *pchanges = talloc_move(mem_ctx, &state->changes);
5071         return NT_STATUS_OK;
5072 }
5073
5074 NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
5075                     uint32_t completion_filter, bool recursive,
5076                     TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
5077                     struct notify_change **pchanges)
5078 {
5079         TALLOC_CTX *frame = talloc_stackframe();
5080         struct tevent_context *ev;
5081         struct tevent_req *req;
5082         NTSTATUS status = NT_STATUS_NO_MEMORY;
5083
5084         if (smbXcli_conn_has_async_calls(cli->conn)) {
5085                 /*
5086                  * Can't use sync call while an async call is in flight
5087                  */
5088                 status = NT_STATUS_INVALID_PARAMETER;
5089                 goto fail;
5090         }
5091         ev = samba_tevent_context_init(frame);
5092         if (ev == NULL) {
5093                 goto fail;
5094         }
5095         req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
5096                               completion_filter, recursive);
5097         if (req == NULL) {
5098                 goto fail;
5099         }
5100         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5101                 goto fail;
5102         }
5103         status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
5104  fail:
5105         TALLOC_FREE(frame);
5106         return status;
5107 }
5108
5109 struct cli_qpathinfo_state {
5110         uint8_t *param;
5111         uint8_t *data;
5112         uint16_t setup[1];
5113         uint32_t min_rdata;
5114         uint8_t *rdata;
5115         uint32_t num_rdata;
5116 };
5117
5118 static void cli_qpathinfo_done(struct tevent_req *subreq);
5119
5120 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
5121                                       struct tevent_context *ev,
5122                                       struct cli_state *cli, const char *fname,
5123                                       uint16_t level, uint32_t min_rdata,
5124                                       uint32_t max_rdata)
5125 {
5126         struct tevent_req *req, *subreq;
5127         struct cli_qpathinfo_state *state;
5128
5129         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
5130         if (req == NULL) {
5131                 return NULL;
5132         }
5133         state->min_rdata = min_rdata;
5134         SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
5135
5136         state->param = talloc_zero_array(state, uint8_t, 6);
5137         if (tevent_req_nomem(state->param, req)) {
5138                 return tevent_req_post(req, ev);
5139         }
5140         SSVAL(state->param, 0, level);
5141         state->param = trans2_bytes_push_str(
5142                 state->param, smbXcli_conn_use_unicode(cli->conn), fname, strlen(fname)+1, NULL);
5143         if (tevent_req_nomem(state->param, req)) {
5144                 return tevent_req_post(req, ev);
5145         }
5146
5147         subreq = cli_trans_send(
5148                 state,                  /* mem ctx. */
5149                 ev,                     /* event ctx. */
5150                 cli,                    /* cli_state. */
5151                 SMBtrans2,              /* cmd. */
5152                 NULL,                   /* pipe name. */
5153                 -1,                     /* fid. */
5154                 0,                      /* function. */
5155                 0,                      /* flags. */
5156                 state->setup,           /* setup. */
5157                 1,                      /* num setup uint16_t words. */
5158                 0,                      /* max returned setup. */
5159                 state->param,           /* param. */
5160                 talloc_get_size(state->param),  /* num param. */
5161                 2,                      /* max returned param. */
5162                 NULL,                   /* data. */
5163                 0,                      /* num data. */
5164                 max_rdata);             /* max returned data. */
5165
5166         if (tevent_req_nomem(subreq, req)) {
5167                 return tevent_req_post(req, ev);
5168         }
5169         tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5170         return req;
5171 }
5172
5173 static void cli_qpathinfo_done(struct tevent_req *subreq)
5174 {
5175         struct tevent_req *req = tevent_req_callback_data(
5176                 subreq, struct tevent_req);
5177         struct cli_qpathinfo_state *state = tevent_req_data(
5178                 req, struct cli_qpathinfo_state);
5179         NTSTATUS status;
5180
5181         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5182                                 NULL, 0, NULL,
5183                                 &state->rdata, state->min_rdata,
5184                                 &state->num_rdata);
5185         if (tevent_req_nterror(req, status)) {
5186                 return;
5187         }
5188         tevent_req_done(req);
5189 }
5190
5191 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5192                             uint8_t **rdata, uint32_t *num_rdata)
5193 {
5194         struct cli_qpathinfo_state *state = tevent_req_data(
5195                 req, struct cli_qpathinfo_state);
5196         NTSTATUS status;
5197
5198         if (tevent_req_is_nterror(req, &status)) {
5199                 return status;
5200         }
5201         if (rdata != NULL) {
5202                 *rdata = talloc_move(mem_ctx, &state->rdata);
5203         } else {
5204                 TALLOC_FREE(state->rdata);
5205         }
5206         if (num_rdata != NULL) {
5207                 *num_rdata = state->num_rdata;
5208         }
5209         return NT_STATUS_OK;
5210 }
5211
5212 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5213                        const char *fname, uint16_t level, uint32_t min_rdata,
5214                        uint32_t max_rdata,
5215                        uint8_t **rdata, uint32_t *num_rdata)
5216 {
5217         TALLOC_CTX *frame = talloc_stackframe();
5218         struct tevent_context *ev;
5219         struct tevent_req *req;
5220         NTSTATUS status = NT_STATUS_NO_MEMORY;
5221
5222         if (smbXcli_conn_has_async_calls(cli->conn)) {
5223                 /*
5224                  * Can't use sync call while an async call is in flight
5225                  */
5226                 status = NT_STATUS_INVALID_PARAMETER;
5227                 goto fail;
5228         }
5229         ev = samba_tevent_context_init(frame);
5230         if (ev == NULL) {
5231                 goto fail;
5232         }
5233         req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5234                                  max_rdata);
5235         if (req == NULL) {
5236                 goto fail;
5237         }
5238         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5239                 goto fail;
5240         }
5241         status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5242  fail:
5243         TALLOC_FREE(frame);
5244         return status;
5245 }
5246
5247 struct cli_qfileinfo_state {
5248         uint16_t setup[1];
5249         uint8_t param[4];
5250         uint8_t *data;
5251         uint16_t recv_flags2;
5252         uint32_t min_rdata;
5253         uint8_t *rdata;
5254         uint32_t num_rdata;
5255 };
5256
5257 static void cli_qfileinfo_done(struct tevent_req *subreq);
5258
5259 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
5260                                       struct tevent_context *ev,
5261                                       struct cli_state *cli, uint16_t fnum,
5262                                       uint16_t level, uint32_t min_rdata,
5263                                       uint32_t max_rdata)
5264 {
5265         struct tevent_req *req, *subreq;
5266         struct cli_qfileinfo_state *state;
5267
5268         req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
5269         if (req == NULL) {
5270                 return NULL;
5271         }
5272         state->min_rdata = min_rdata;
5273         SSVAL(state->param, 0, fnum);
5274         SSVAL(state->param, 2, level);
5275         SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
5276
5277         subreq = cli_trans_send(
5278                 state,                  /* mem ctx. */
5279                 ev,                     /* event ctx. */
5280                 cli,                    /* cli_state. */
5281                 SMBtrans2,              /* cmd. */
5282                 NULL,                   /* pipe name. */
5283                 -1,                     /* fid. */
5284                 0,                      /* function. */
5285                 0,                      /* flags. */
5286                 state->setup,           /* setup. */
5287                 1,                      /* num setup uint16_t words. */
5288                 0,                      /* max returned setup. */
5289                 state->param,           /* param. */
5290                 sizeof(state->param),   /* num param. */
5291                 2,                      /* max returned param. */
5292                 NULL,                   /* data. */
5293                 0,                      /* num data. */
5294                 max_rdata);             /* max returned data. */
5295
5296         if (tevent_req_nomem(subreq, req)) {
5297                 return tevent_req_post(req, ev);
5298         }
5299         tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
5300         return req;
5301 }
5302
5303 static void cli_qfileinfo_done(struct tevent_req *subreq)
5304 {
5305         struct tevent_req *req = tevent_req_callback_data(
5306                 subreq, struct tevent_req);
5307         struct cli_qfileinfo_state *state = tevent_req_data(
5308                 req, struct cli_qfileinfo_state);
5309         NTSTATUS status;
5310
5311         status = cli_trans_recv(subreq, state,
5312                                 &state->recv_flags2,
5313                                 NULL, 0, NULL,
5314                                 NULL, 0, NULL,
5315                                 &state->rdata, state->min_rdata,
5316                                 &state->num_rdata);
5317         if (tevent_req_nterror(req, status)) {
5318                 return;
5319         }
5320         tevent_req_done(req);
5321 }
5322
5323 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5324                             uint16_t *recv_flags2,
5325                             uint8_t **rdata, uint32_t *num_rdata)
5326 {
5327         struct cli_qfileinfo_state *state = tevent_req_data(
5328                 req, struct cli_qfileinfo_state);
5329         NTSTATUS status;
5330
5331         if (tevent_req_is_nterror(req, &status)) {
5332                 return status;
5333         }
5334
5335         if (recv_flags2 != NULL) {
5336                 *recv_flags2 = state->recv_flags2;
5337         }
5338         if (rdata != NULL) {
5339                 *rdata = talloc_move(mem_ctx, &state->rdata);
5340         } else {
5341                 TALLOC_FREE(state->rdata);
5342         }
5343         if (num_rdata != NULL) {
5344                 *num_rdata = state->num_rdata;
5345         }
5346         return NT_STATUS_OK;
5347 }
5348
5349 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5350                        uint16_t fnum, uint16_t level, uint32_t min_rdata,
5351                        uint32_t max_rdata, uint16_t *recv_flags2,
5352                        uint8_t **rdata, uint32_t *num_rdata)
5353 {
5354         TALLOC_CTX *frame = talloc_stackframe();
5355         struct tevent_context *ev;
5356         struct tevent_req *req;
5357         NTSTATUS status = NT_STATUS_NO_MEMORY;
5358
5359         if (smbXcli_conn_has_async_calls(cli->conn)) {
5360                 /*
5361                  * Can't use sync call while an async call is in flight
5362                  */
5363                 status = NT_STATUS_INVALID_PARAMETER;
5364                 goto fail;
5365         }
5366         ev = samba_tevent_context_init(frame);
5367         if (ev == NULL) {
5368                 goto fail;
5369         }
5370         req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
5371                                  max_rdata);
5372         if (req == NULL) {
5373                 goto fail;
5374         }
5375         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5376                 goto fail;
5377         }
5378         status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
5379  fail:
5380         TALLOC_FREE(frame);
5381         return status;
5382 }
5383
5384 struct cli_flush_state {
5385         uint16_t vwv[1];
5386 };
5387
5388 static void cli_flush_done(struct tevent_req *subreq);
5389
5390 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
5391                                   struct tevent_context *ev,
5392                                   struct cli_state *cli,
5393                                   uint16_t fnum)
5394 {
5395         struct tevent_req *req, *subreq;
5396         struct cli_flush_state *state;
5397
5398         req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
5399         if (req == NULL) {
5400                 return NULL;
5401         }
5402         SSVAL(state->vwv + 0, 0, fnum);
5403
5404         subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 1, state->vwv,
5405                               0, NULL);
5406         if (tevent_req_nomem(subreq, req)) {
5407                 return tevent_req_post(req, ev);
5408         }
5409         tevent_req_set_callback(subreq, cli_flush_done, req);
5410         return req;
5411 }
5412
5413 static void cli_flush_done(struct tevent_req *subreq)
5414 {
5415         struct tevent_req *req = tevent_req_callback_data(
5416                 subreq, struct tevent_req);
5417         NTSTATUS status;
5418
5419         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5420         TALLOC_FREE(subreq);
5421         if (tevent_req_nterror(req, status)) {
5422                 return;
5423         }
5424         tevent_req_done(req);
5425 }
5426
5427 NTSTATUS cli_flush_recv(struct tevent_req *req)
5428 {
5429         return tevent_req_simple_recv_ntstatus(req);
5430 }
5431
5432 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
5433 {
5434         TALLOC_CTX *frame = talloc_stackframe();
5435         struct tevent_context *ev;
5436         struct tevent_req *req;
5437         NTSTATUS status = NT_STATUS_NO_MEMORY;
5438
5439         if (smbXcli_conn_has_async_calls(cli->conn)) {
5440                 /*
5441                  * Can't use sync call while an async call is in flight
5442                  */
5443                 status = NT_STATUS_INVALID_PARAMETER;
5444                 goto fail;
5445         }
5446         ev = samba_tevent_context_init(frame);
5447         if (ev == NULL) {
5448                 goto fail;
5449         }
5450         req = cli_flush_send(frame, ev, cli, fnum);
5451         if (req == NULL) {
5452                 goto fail;
5453         }
5454         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5455                 goto fail;
5456         }
5457         status = cli_flush_recv(req);
5458  fail:
5459         TALLOC_FREE(frame);
5460         return status;
5461 }
5462
5463 struct cli_shadow_copy_data_state {
5464         uint16_t setup[4];
5465         uint8_t *data;
5466         uint32_t num_data;
5467         bool get_names;
5468 };
5469
5470 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
5471
5472 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
5473                                              struct tevent_context *ev,
5474                                              struct cli_state *cli,
5475                                              uint16_t fnum,
5476                                              bool get_names)
5477 {
5478         struct tevent_req *req, *subreq;
5479         struct cli_shadow_copy_data_state *state;
5480         uint32_t ret_size;
5481
5482         req = tevent_req_create(mem_ctx, &state,
5483                                 struct cli_shadow_copy_data_state);
5484         if (req == NULL) {
5485                 return NULL;
5486         }
5487         state->get_names = get_names;
5488         ret_size = get_names ? CLI_BUFFER_SIZE : 16;
5489
5490         SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
5491         SSVAL(state->setup + 2, 0, fnum);
5492         SCVAL(state->setup + 3, 0, 1); /* isFsctl */
5493         SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
5494
5495         subreq = cli_trans_send(
5496                 state, ev, cli, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
5497                 state->setup, ARRAY_SIZE(state->setup), 0,
5498                 NULL, 0, 0,
5499                 NULL, 0, ret_size);
5500         if (tevent_req_nomem(subreq, req)) {
5501                 return tevent_req_post(req, ev);
5502         }
5503         tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
5504         return req;
5505 }
5506
5507 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
5508 {
5509         struct tevent_req *req = tevent_req_callback_data(
5510                 subreq, struct tevent_req);
5511         struct cli_shadow_copy_data_state *state = tevent_req_data(
5512                 req, struct cli_shadow_copy_data_state);
5513         NTSTATUS status;
5514
5515         status = cli_trans_recv(subreq, state, NULL,
5516                                 NULL, 0, NULL, /* setup */
5517                                 NULL, 0, NULL, /* param */
5518                                 &state->data, 12, &state->num_data);
5519         TALLOC_FREE(subreq);
5520         if (tevent_req_nterror(req, status)) {
5521                 return;
5522         }
5523         tevent_req_done(req);
5524 }
5525
5526 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5527                                    char ***pnames, int *pnum_names)
5528 {
5529         struct cli_shadow_copy_data_state *state = tevent_req_data(
5530                 req, struct cli_shadow_copy_data_state);
5531         char **names;
5532         int i, num_names;
5533         uint32_t dlength;
5534         NTSTATUS status;
5535
5536         if (tevent_req_is_nterror(req, &status)) {
5537                 return status;
5538         }
5539         num_names = IVAL(state->data, 4);
5540         dlength = IVAL(state->data, 8);
5541
5542         if (!state->get_names) {
5543                 *pnum_names = num_names;
5544                 return NT_STATUS_OK;
5545         }
5546
5547         if (dlength+12 > state->num_data) {
5548                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5549         }
5550         names = talloc_array(mem_ctx, char *, num_names);
5551         if (names == NULL) {
5552                 return NT_STATUS_NO_MEMORY;
5553         }
5554
5555         for (i=0; i<num_names; i++) {
5556                 bool ret;
5557                 uint8_t *src;
5558                 size_t converted_size;
5559
5560                 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
5561                 ret = convert_string_talloc(
5562                         names, CH_UTF16LE, CH_UNIX,
5563                         src, 2 * sizeof(SHADOW_COPY_LABEL),
5564                         &names[i], &converted_size);
5565                 if (!ret) {
5566                         TALLOC_FREE(names);
5567                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
5568                 }
5569         }
5570         *pnum_names = num_names;
5571         *pnames = names;
5572         return NT_STATUS_OK;
5573 }
5574
5575 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5576                               uint16_t fnum, bool get_names,
5577                               char ***pnames, int *pnum_names)
5578 {
5579         TALLOC_CTX *frame = talloc_stackframe();
5580         struct tevent_context *ev;
5581         struct tevent_req *req;
5582         NTSTATUS status = NT_STATUS_NO_MEMORY;
5583
5584         if (smbXcli_conn_has_async_calls(cli->conn)) {
5585                 /*
5586                  * Can't use sync call while an async call is in flight
5587                  */
5588                 status = NT_STATUS_INVALID_PARAMETER;
5589                 goto fail;
5590         }
5591         ev = samba_tevent_context_init(frame);
5592         if (ev == NULL) {
5593                 goto fail;
5594         }
5595         req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
5596         if (req == NULL) {
5597                 goto fail;
5598         }
5599         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5600                 goto fail;
5601         }
5602         status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
5603  fail:
5604         TALLOC_FREE(frame);
5605         return status;
5606 }