3bdb49d6d40c560046ca682dadca3b6ce24b1e76
[kai/samba.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "libsmb/libsmb.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "async_smb.h"
26 #include "libsmb/clirap.h"
27 #include "trans2.h"
28 #include "ntioctl.h"
29 #include "libcli/security/secdesc.h"
30 #include "../libcli/smb/smbXcli_base.h"
31
32 /***********************************************************
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 = 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 event_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 event_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 event_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 = event_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 event_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 event_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 = event_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 event_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 event_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 = event_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 event_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 event_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 = event_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 event_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 event_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 = event_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 event_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 event_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 event_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 = event_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 event_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 event_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 = event_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 event_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 event_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 = event_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 event_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 event_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 event_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 = event_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 event_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 event_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 = event_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 event_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 event_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 = event_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 event_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 event_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 = event_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 event_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 event_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 = event_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 event_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 event_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 = event_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 event_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         uint8_t *inbuf;
1856         NTSTATUS status;
1857
1858         status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv,
1859                               &num_bytes, &bytes);
1860         TALLOC_FREE(subreq);
1861         if (tevent_req_nterror(req, status)) {
1862                 return;
1863         }
1864         state->fnum = SVAL(vwv+2, 1);
1865         tevent_req_done(req);
1866 }
1867
1868 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
1869 {
1870         struct cli_ntcreate_state *state = tevent_req_data(
1871                 req, struct cli_ntcreate_state);
1872         NTSTATUS status;
1873
1874         if (tevent_req_is_nterror(req, &status)) {
1875                 return status;
1876         }
1877         *pfnum = state->fnum;
1878         return NT_STATUS_OK;
1879 }
1880
1881 NTSTATUS cli_ntcreate(struct cli_state *cli,
1882                       const char *fname,
1883                       uint32_t CreatFlags,
1884                       uint32_t DesiredAccess,
1885                       uint32_t FileAttributes,
1886                       uint32_t ShareAccess,
1887                       uint32_t CreateDisposition,
1888                       uint32_t CreateOptions,
1889                       uint8_t SecurityFlags,
1890                       uint16_t *pfid)
1891 {
1892         TALLOC_CTX *frame = talloc_stackframe();
1893         struct event_context *ev;
1894         struct tevent_req *req;
1895         NTSTATUS status = NT_STATUS_OK;
1896
1897         if (smbXcli_conn_has_async_calls(cli->conn)) {
1898                 /*
1899                  * Can't use sync call while an async call is in flight
1900                  */
1901                 status = NT_STATUS_INVALID_PARAMETER;
1902                 goto fail;
1903         }
1904
1905         ev = event_context_init(frame);
1906         if (ev == NULL) {
1907                 status = NT_STATUS_NO_MEMORY;
1908                 goto fail;
1909         }
1910
1911         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
1912                                 DesiredAccess, FileAttributes, ShareAccess,
1913                                 CreateDisposition, CreateOptions,
1914                                 SecurityFlags);
1915         if (req == NULL) {
1916                 status = NT_STATUS_NO_MEMORY;
1917                 goto fail;
1918         }
1919
1920         if (!tevent_req_poll(req, ev)) {
1921                 status = map_nt_error_from_unix(errno);
1922                 goto fail;
1923         }
1924
1925         status = cli_ntcreate_recv(req, pfid);
1926  fail:
1927         TALLOC_FREE(frame);
1928         return status;
1929 }
1930
1931 struct cli_nttrans_create_state {
1932         uint16_t fnum;
1933 };
1934
1935 static void cli_nttrans_create_done(struct tevent_req *subreq);
1936
1937 struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
1938                                            struct event_context *ev,
1939                                            struct cli_state *cli,
1940                                            const char *fname,
1941                                            uint32_t CreatFlags,
1942                                            uint32_t DesiredAccess,
1943                                            uint32_t FileAttributes,
1944                                            uint32_t ShareAccess,
1945                                            uint32_t CreateDisposition,
1946                                            uint32_t CreateOptions,
1947                                            uint8_t SecurityFlags,
1948                                            struct security_descriptor *secdesc,
1949                                            struct ea_struct *eas,
1950                                            int num_eas)
1951 {
1952         struct tevent_req *req, *subreq;
1953         struct cli_nttrans_create_state *state;
1954         uint8_t *param;
1955         uint8_t *secdesc_buf;
1956         size_t secdesc_len;
1957         NTSTATUS status;
1958         size_t converted_len;
1959
1960         req = tevent_req_create(mem_ctx,
1961                                 &state, struct cli_nttrans_create_state);
1962         if (req == NULL) {
1963                 return NULL;
1964         }
1965
1966         if (secdesc != NULL) {
1967                 status = marshall_sec_desc(talloc_tos(), secdesc,
1968                                            &secdesc_buf, &secdesc_len);
1969                 if (tevent_req_nterror(req, status)) {
1970                         DEBUG(10, ("marshall_sec_desc failed: %s\n",
1971                                    nt_errstr(status)));
1972                         return tevent_req_post(req, ev);
1973                 }
1974         } else {
1975                 secdesc_buf = NULL;
1976                 secdesc_len = 0;
1977         }
1978
1979         if (num_eas != 0) {
1980                 /*
1981                  * TODO ;-)
1982                  */
1983                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
1984                 return tevent_req_post(req, ev);
1985         }
1986
1987         param = talloc_array(state, uint8_t, 53);
1988         if (tevent_req_nomem(param, req)) {
1989                 return tevent_req_post(req, ev);
1990         }
1991
1992         param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
1993                                       fname, strlen(fname),
1994                                       &converted_len);
1995         if (tevent_req_nomem(param, req)) {
1996                 return tevent_req_post(req, ev);
1997         }
1998
1999         SIVAL(param, 0, CreatFlags);
2000         SIVAL(param, 4, 0x0);   /* RootDirectoryFid */
2001         SIVAL(param, 8, DesiredAccess);
2002         SIVAL(param, 12, 0x0);  /* AllocationSize */
2003         SIVAL(param, 16, 0x0);  /* AllocationSize */
2004         SIVAL(param, 20, FileAttributes);
2005         SIVAL(param, 24, ShareAccess);
2006         SIVAL(param, 28, CreateDisposition);
2007         SIVAL(param, 32, CreateOptions |
2008                 (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2009         SIVAL(param, 36, secdesc_len);
2010         SIVAL(param, 40, 0);     /* EA length*/
2011         SIVAL(param, 44, converted_len);
2012         SIVAL(param, 48, 0x02); /* ImpersonationLevel */
2013         SCVAL(param, 52, SecurityFlags);
2014
2015         subreq = cli_trans_send(state, ev, cli, SMBnttrans,
2016                                 NULL, -1, /* name, fid */
2017                                 NT_TRANSACT_CREATE, 0,
2018                                 NULL, 0, 0, /* setup */
2019                                 param, talloc_get_size(param), 128, /* param */
2020                                 secdesc_buf, secdesc_len, 0); /* data */
2021         if (tevent_req_nomem(subreq, req)) {
2022                 return tevent_req_post(req, ev);
2023         }
2024         tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
2025         return req;
2026 }
2027
2028 static void cli_nttrans_create_done(struct tevent_req *subreq)
2029 {
2030         struct tevent_req *req = tevent_req_callback_data(
2031                 subreq, struct tevent_req);
2032         struct cli_nttrans_create_state *state = tevent_req_data(
2033                 req, struct cli_nttrans_create_state);
2034         uint8_t *param;
2035         uint32_t num_param;
2036         NTSTATUS status;
2037
2038         status = cli_trans_recv(subreq, talloc_tos(), NULL,
2039                                 NULL, 0, NULL, /* rsetup */
2040                                 &param, 69, &num_param,
2041                                 NULL, 0, NULL);
2042         if (tevent_req_nterror(req, status)) {
2043                 return;
2044         }
2045         state->fnum = SVAL(param, 2);
2046         TALLOC_FREE(param);
2047         tevent_req_done(req);
2048 }
2049
2050 NTSTATUS cli_nttrans_create_recv(struct tevent_req *req, uint16_t *fnum)
2051 {
2052         struct cli_nttrans_create_state *state = tevent_req_data(
2053                 req, struct cli_nttrans_create_state);
2054         NTSTATUS status;
2055
2056         if (tevent_req_is_nterror(req, &status)) {
2057                 return status;
2058         }
2059         *fnum = state->fnum;
2060         return NT_STATUS_OK;
2061 }
2062
2063 NTSTATUS cli_nttrans_create(struct cli_state *cli,
2064                             const char *fname,
2065                             uint32_t CreatFlags,
2066                             uint32_t DesiredAccess,
2067                             uint32_t FileAttributes,
2068                             uint32_t ShareAccess,
2069                             uint32_t CreateDisposition,
2070                             uint32_t CreateOptions,
2071                             uint8_t SecurityFlags,
2072                             struct security_descriptor *secdesc,
2073                             struct ea_struct *eas,
2074                             int num_eas,
2075                             uint16_t *pfid)
2076 {
2077         TALLOC_CTX *frame = talloc_stackframe();
2078         struct event_context *ev;
2079         struct tevent_req *req;
2080         NTSTATUS status = NT_STATUS_NO_MEMORY;
2081
2082         if (smbXcli_conn_has_async_calls(cli->conn)) {
2083                 /*
2084                  * Can't use sync call while an async call is in flight
2085                  */
2086                 status = NT_STATUS_INVALID_PARAMETER;
2087                 goto fail;
2088         }
2089         ev = event_context_init(frame);
2090         if (ev == NULL) {
2091                 goto fail;
2092         }
2093         req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
2094                                       DesiredAccess, FileAttributes,
2095                                       ShareAccess, CreateDisposition,
2096                                       CreateOptions, SecurityFlags,
2097                                       secdesc, eas, num_eas);
2098         if (req == NULL) {
2099                 goto fail;
2100         }
2101         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2102                 goto fail;
2103         }
2104         status = cli_nttrans_create_recv(req, pfid);
2105  fail:
2106         TALLOC_FREE(frame);
2107         return status;
2108 }
2109
2110 /****************************************************************************
2111  Open a file
2112  WARNING: if you open with O_WRONLY then getattrE won't work!
2113 ****************************************************************************/
2114
2115 struct cli_openx_state {
2116         const char *fname;
2117         uint16_t vwv[15];
2118         uint16_t fnum;
2119         struct iovec bytes;
2120 };
2121
2122 static void cli_openx_done(struct tevent_req *subreq);
2123
2124 struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
2125                                    struct event_context *ev,
2126                                    struct cli_state *cli, const char *fname,
2127                                    int flags, int share_mode,
2128                                    struct tevent_req **psmbreq)
2129 {
2130         struct tevent_req *req, *subreq;
2131         struct cli_openx_state *state;
2132         unsigned openfn;
2133         unsigned accessmode;
2134         uint8_t additional_flags;
2135         uint8_t *bytes;
2136
2137         req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
2138         if (req == NULL) {
2139                 return NULL;
2140         }
2141
2142         openfn = 0;
2143         if (flags & O_CREAT) {
2144                 openfn |= (1<<4);
2145         }
2146         if (!(flags & O_EXCL)) {
2147                 if (flags & O_TRUNC)
2148                         openfn |= (1<<1);
2149                 else
2150                         openfn |= (1<<0);
2151         }
2152
2153         accessmode = (share_mode<<4);
2154
2155         if ((flags & O_ACCMODE) == O_RDWR) {
2156                 accessmode |= 2;
2157         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2158                 accessmode |= 1;
2159         }
2160
2161 #if defined(O_SYNC)
2162         if ((flags & O_SYNC) == O_SYNC) {
2163                 accessmode |= (1<<14);
2164         }
2165 #endif /* O_SYNC */
2166
2167         if (share_mode == DENY_FCB) {
2168                 accessmode = 0xFF;
2169         }
2170
2171         SCVAL(state->vwv + 0, 0, 0xFF);
2172         SCVAL(state->vwv + 0, 1, 0);
2173         SSVAL(state->vwv + 1, 0, 0);
2174         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
2175         SSVAL(state->vwv + 3, 0, accessmode);
2176         SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2177         SSVAL(state->vwv + 5, 0, 0);
2178         SIVAL(state->vwv + 6, 0, 0);
2179         SSVAL(state->vwv + 8, 0, openfn);
2180         SIVAL(state->vwv + 9, 0, 0);
2181         SIVAL(state->vwv + 11, 0, 0);
2182         SIVAL(state->vwv + 13, 0, 0);
2183
2184         additional_flags = 0;
2185
2186         if (cli->use_oplocks) {
2187                 /* if using oplocks then ask for a batch oplock via
2188                    core and extended methods */
2189                 additional_flags =
2190                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2191                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2192         }
2193
2194         bytes = talloc_array(state, uint8_t, 0);
2195         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
2196                                    strlen(fname)+1, NULL);
2197
2198         if (tevent_req_nomem(bytes, req)) {
2199                 return tevent_req_post(req, ev);
2200         }
2201
2202         state->bytes.iov_base = (void *)bytes;
2203         state->bytes.iov_len = talloc_get_size(bytes);
2204
2205         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2206                                     15, state->vwv, 1, &state->bytes);
2207         if (subreq == NULL) {
2208                 TALLOC_FREE(req);
2209                 return NULL;
2210         }
2211         tevent_req_set_callback(subreq, cli_openx_done, req);
2212         *psmbreq = subreq;
2213         return req;
2214 }
2215
2216 struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
2217                                  struct cli_state *cli, const char *fname,
2218                                  int flags, int share_mode)
2219 {
2220         struct tevent_req *req, *subreq;
2221         NTSTATUS status;
2222
2223         req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
2224                               &subreq);
2225         if (req == NULL) {
2226                 return NULL;
2227         }
2228
2229         status = cli_smb_req_send(subreq);
2230         if (tevent_req_nterror(req, status)) {
2231                 return tevent_req_post(req, ev);
2232         }
2233         return req;
2234 }
2235
2236 static void cli_openx_done(struct tevent_req *subreq)
2237 {
2238         struct tevent_req *req = tevent_req_callback_data(
2239                 subreq, struct tevent_req);
2240         struct cli_openx_state *state = tevent_req_data(
2241                 req, struct cli_openx_state);
2242         uint8_t wct;
2243         uint16_t *vwv;
2244         uint8_t *inbuf;
2245         NTSTATUS status;
2246
2247         status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv, NULL,
2248                               NULL);
2249         TALLOC_FREE(subreq);
2250         if (tevent_req_nterror(req, status)) {
2251                 return;
2252         }
2253         state->fnum = SVAL(vwv+2, 0);
2254         tevent_req_done(req);
2255 }
2256
2257 NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
2258 {
2259         struct cli_openx_state *state = tevent_req_data(
2260                 req, struct cli_openx_state);
2261         NTSTATUS status;
2262
2263         if (tevent_req_is_nterror(req, &status)) {
2264                 return status;
2265         }
2266         *pfnum = state->fnum;
2267         return NT_STATUS_OK;
2268 }
2269
2270 NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
2271              int share_mode, uint16_t *pfnum)
2272 {
2273         TALLOC_CTX *frame = talloc_stackframe();
2274         struct event_context *ev;
2275         struct tevent_req *req;
2276         NTSTATUS status = NT_STATUS_OK;
2277
2278         if (smbXcli_conn_has_async_calls(cli->conn)) {
2279                 /*
2280                  * Can't use sync call while an async call is in flight
2281                  */
2282                 status = NT_STATUS_INVALID_PARAMETER;
2283                 goto fail;
2284         }
2285
2286         ev = event_context_init(frame);
2287         if (ev == NULL) {
2288                 status = NT_STATUS_NO_MEMORY;
2289                 goto fail;
2290         }
2291
2292         req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
2293         if (req == NULL) {
2294                 status = NT_STATUS_NO_MEMORY;
2295                 goto fail;
2296         }
2297
2298         if (!tevent_req_poll(req, ev)) {
2299                 status = map_nt_error_from_unix(errno);
2300                 goto fail;
2301         }
2302
2303         status = cli_openx_recv(req, pfnum);
2304  fail:
2305         TALLOC_FREE(frame);
2306         return status;
2307 }
2308 /****************************************************************************
2309  Synchronous wrapper function that does an NtCreateX open by preference
2310  and falls back to openX if this fails.
2311 ****************************************************************************/
2312
2313 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2314                         int share_mode_in, uint16_t *pfnum)
2315 {
2316         NTSTATUS status;
2317         unsigned int openfn = 0;
2318         unsigned int dos_deny = 0;
2319         uint32_t access_mask, share_mode, create_disposition, create_options;
2320
2321         /* Do the initial mapping into OpenX parameters. */
2322         if (flags & O_CREAT) {
2323                 openfn |= (1<<4);
2324         }
2325         if (!(flags & O_EXCL)) {
2326                 if (flags & O_TRUNC)
2327                         openfn |= (1<<1);
2328                 else
2329                         openfn |= (1<<0);
2330         }
2331
2332         dos_deny = (share_mode_in<<4);
2333
2334         if ((flags & O_ACCMODE) == O_RDWR) {
2335                 dos_deny |= 2;
2336         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2337                 dos_deny |= 1;
2338         }
2339
2340 #if defined(O_SYNC)
2341         if ((flags & O_SYNC) == O_SYNC) {
2342                 dos_deny |= (1<<14);
2343         }
2344 #endif /* O_SYNC */
2345
2346         if (share_mode_in == DENY_FCB) {
2347                 dos_deny = 0xFF;
2348         }
2349
2350 #if 0
2351         /* Hmmm. This is what I think the above code
2352            should look like if it's using the constants
2353            we #define. JRA. */
2354
2355         if (flags & O_CREAT) {
2356                 openfn |= OPENX_FILE_CREATE_IF_NOT_EXIST;
2357         }
2358         if (!(flags & O_EXCL)) {
2359                 if (flags & O_TRUNC)
2360                         openfn |= OPENX_FILE_EXISTS_TRUNCATE;
2361                 else
2362                         openfn |= OPENX_FILE_EXISTS_OPEN;
2363         }
2364
2365         dos_deny = SET_DENY_MODE(share_mode_in);
2366
2367         if ((flags & O_ACCMODE) == O_RDWR) {
2368                 dos_deny |= DOS_OPEN_RDWR;
2369         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2370                 dos_deny |= DOS_OPEN_WRONLY;
2371         }
2372
2373 #if defined(O_SYNC)
2374         if ((flags & O_SYNC) == O_SYNC) {
2375                 dos_deny |= FILE_SYNC_OPENMODE;
2376         }
2377 #endif /* O_SYNC */
2378
2379         if (share_mode_in == DENY_FCB) {
2380                 dos_deny = 0xFF;
2381         }
2382 #endif
2383
2384         if (!map_open_params_to_ntcreate(fname, dos_deny,
2385                                         openfn, &access_mask,
2386                                         &share_mode, &create_disposition,
2387                                         &create_options, NULL)) {
2388                 goto try_openx;
2389         }
2390
2391         status = cli_ntcreate(cli,
2392                                 fname,
2393                                 0,
2394                                 access_mask,
2395                                 0,
2396                                 share_mode,
2397                                 create_disposition,
2398                                 create_options,
2399                                 0,
2400                                 pfnum);
2401
2402         /* Try and cope will all varients of "we don't do this call"
2403            and fall back to openX. */
2404
2405         if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
2406                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
2407                         NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
2408                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
2409                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
2410                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
2411                         NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
2412                         NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
2413                         NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
2414                 goto try_openx;
2415         }
2416
2417         return status;
2418
2419   try_openx:
2420
2421         return cli_openx(cli, fname, flags, share_mode_in, pfnum);
2422 }
2423
2424 /****************************************************************************
2425  Close a file.
2426 ****************************************************************************/
2427
2428 struct cli_close_state {
2429         uint16_t vwv[3];
2430 };
2431
2432 static void cli_close_done(struct tevent_req *subreq);
2433
2434 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2435                                 struct event_context *ev,
2436                                 struct cli_state *cli,
2437                                 uint16_t fnum,
2438                                 struct tevent_req **psubreq)
2439 {
2440         struct tevent_req *req, *subreq;
2441         struct cli_close_state *state;
2442
2443         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2444         if (req == NULL) {
2445                 return NULL;
2446         }
2447
2448         SSVAL(state->vwv+0, 0, fnum);
2449         SIVALS(state->vwv+1, 0, -1);
2450
2451         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2452                                     0, NULL);
2453         if (subreq == NULL) {
2454                 TALLOC_FREE(req);
2455                 return NULL;
2456         }
2457         tevent_req_set_callback(subreq, cli_close_done, req);
2458         *psubreq = subreq;
2459         return req;
2460 }
2461
2462 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2463                                 struct event_context *ev,
2464                                 struct cli_state *cli,
2465                                 uint16_t fnum)
2466 {
2467         struct tevent_req *req, *subreq;
2468         NTSTATUS status;
2469
2470         req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2471         if (req == NULL) {
2472                 return NULL;
2473         }
2474
2475         status = cli_smb_req_send(subreq);
2476         if (tevent_req_nterror(req, status)) {
2477                 return tevent_req_post(req, ev);
2478         }
2479         return req;
2480 }
2481
2482 static void cli_close_done(struct tevent_req *subreq)
2483 {
2484         struct tevent_req *req = tevent_req_callback_data(
2485                 subreq, struct tevent_req);
2486         NTSTATUS status;
2487
2488         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2489         TALLOC_FREE(subreq);
2490         if (tevent_req_nterror(req, status)) {
2491                 return;
2492         }
2493         tevent_req_done(req);
2494 }
2495
2496 NTSTATUS cli_close_recv(struct tevent_req *req)
2497 {
2498         return tevent_req_simple_recv_ntstatus(req);
2499 }
2500
2501 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2502 {
2503         TALLOC_CTX *frame = talloc_stackframe();
2504         struct event_context *ev;
2505         struct tevent_req *req;
2506         NTSTATUS status = NT_STATUS_OK;
2507
2508         if (smbXcli_conn_has_async_calls(cli->conn)) {
2509                 /*
2510                  * Can't use sync call while an async call is in flight
2511                  */
2512                 status = NT_STATUS_INVALID_PARAMETER;
2513                 goto fail;
2514         }
2515
2516         ev = event_context_init(frame);
2517         if (ev == NULL) {
2518                 status = NT_STATUS_NO_MEMORY;
2519                 goto fail;
2520         }
2521
2522         req = cli_close_send(frame, ev, cli, fnum);
2523         if (req == NULL) {
2524                 status = NT_STATUS_NO_MEMORY;
2525                 goto fail;
2526         }
2527
2528         if (!tevent_req_poll(req, ev)) {
2529                 status = map_nt_error_from_unix(errno);
2530                 goto fail;
2531         }
2532
2533         status = cli_close_recv(req);
2534  fail:
2535         TALLOC_FREE(frame);
2536         return status;
2537 }
2538
2539 /****************************************************************************
2540  Truncate a file to a specified size
2541 ****************************************************************************/
2542
2543 struct ftrunc_state {
2544         uint16_t setup;
2545         uint8_t param[6];
2546         uint8_t data[8];
2547 };
2548
2549 static void cli_ftruncate_done(struct tevent_req *subreq)
2550 {
2551         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2552                                          NULL, 0, NULL, NULL, 0, NULL);
2553         tevent_req_simple_finish_ntstatus(subreq, status);
2554 }
2555
2556 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2557                                         struct event_context *ev,
2558                                         struct cli_state *cli,
2559                                         uint16_t fnum,
2560                                         uint64_t size)
2561 {
2562         struct tevent_req *req = NULL, *subreq = NULL;
2563         struct ftrunc_state *state = NULL;
2564
2565         req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2566         if (req == NULL) {
2567                 return NULL;
2568         }
2569
2570         /* Setup setup word. */
2571         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2572
2573         /* Setup param array. */
2574         SSVAL(state->param,0,fnum);
2575         SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2576         SSVAL(state->param,4,0);
2577
2578         /* Setup data array. */
2579         SBVAL(state->data, 0, size);
2580
2581         subreq = cli_trans_send(state,                  /* mem ctx. */
2582                                 ev,                     /* event ctx. */
2583                                 cli,                    /* cli_state. */
2584                                 SMBtrans2,              /* cmd. */
2585                                 NULL,                   /* pipe name. */
2586                                 -1,                     /* fid. */
2587                                 0,                      /* function. */
2588                                 0,                      /* flags. */
2589                                 &state->setup,          /* setup. */
2590                                 1,                      /* num setup uint16_t words. */
2591                                 0,                      /* max returned setup. */
2592                                 state->param,           /* param. */
2593                                 6,                      /* num param. */
2594                                 2,                      /* max returned param. */
2595                                 state->data,            /* data. */
2596                                 8,                      /* num data. */
2597                                 0);                     /* max returned data. */
2598
2599         if (tevent_req_nomem(subreq, req)) {
2600                 return tevent_req_post(req, ev);
2601         }
2602         tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2603         return req;
2604 }
2605
2606 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2607 {
2608         return tevent_req_simple_recv_ntstatus(req);
2609 }
2610
2611 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2612 {
2613         TALLOC_CTX *frame = talloc_stackframe();
2614         struct event_context *ev = NULL;
2615         struct tevent_req *req = NULL;
2616         NTSTATUS status = NT_STATUS_OK;
2617
2618         if (smbXcli_conn_has_async_calls(cli->conn)) {
2619                 /*
2620                  * Can't use sync call while an async call is in flight
2621                  */
2622                 status = NT_STATUS_INVALID_PARAMETER;
2623                 goto fail;
2624         }
2625
2626         ev = event_context_init(frame);
2627         if (ev == NULL) {
2628                 status = NT_STATUS_NO_MEMORY;
2629                 goto fail;
2630         }
2631
2632         req = cli_ftruncate_send(frame,
2633                                 ev,
2634                                 cli,
2635                                 fnum,
2636                                 size);
2637         if (req == NULL) {
2638                 status = NT_STATUS_NO_MEMORY;
2639                 goto fail;
2640         }
2641
2642         if (!tevent_req_poll(req, ev)) {
2643                 status = map_nt_error_from_unix(errno);
2644                 goto fail;
2645         }
2646
2647         status = cli_ftruncate_recv(req);
2648
2649  fail:
2650         TALLOC_FREE(frame);
2651         return status;
2652 }
2653
2654 /****************************************************************************
2655  send a lock with a specified locktype
2656  this is used for testing LOCKING_ANDX_CANCEL_LOCK
2657 ****************************************************************************/
2658
2659 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2660                       uint32_t offset, uint32_t len,
2661                       int timeout, unsigned char locktype)
2662 {
2663         uint16_t vwv[8];
2664         uint8_t bytes[10];
2665         NTSTATUS status;
2666         unsigned int set_timeout = 0;
2667         unsigned int saved_timeout = 0;
2668
2669         SCVAL(vwv + 0, 0, 0xff);
2670         SCVAL(vwv + 0, 1, 0);
2671         SSVAL(vwv + 1, 0, 0);
2672         SSVAL(vwv + 2, 0, fnum);
2673         SCVAL(vwv + 3, 0, locktype);
2674         SCVAL(vwv + 3, 1, 0);
2675         SIVALS(vwv + 4, 0, timeout);
2676         SSVAL(vwv + 6, 0, 0);
2677         SSVAL(vwv + 7, 0, 1);
2678
2679         SSVAL(bytes, 0, cli_getpid(cli));
2680         SIVAL(bytes, 2, offset);
2681         SIVAL(bytes, 6, len);
2682
2683         if (timeout != 0) {
2684                 if (timeout == -1) {
2685                         set_timeout = 0x7FFFFFFF;
2686                 } else {
2687                         set_timeout = timeout + 2*1000;
2688                 }
2689                 saved_timeout = cli_set_timeout(cli, set_timeout);
2690         }
2691
2692         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2693                          10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2694
2695         if (saved_timeout != 0) {
2696                 cli_set_timeout(cli, saved_timeout);
2697         }
2698
2699         return status;
2700 }
2701
2702 /****************************************************************************
2703  Lock a file.
2704  note that timeout is in units of 2 milliseconds
2705 ****************************************************************************/
2706
2707 NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
2708                   uint32_t offset, uint32_t len, int timeout,
2709                   enum brl_type lock_type)
2710 {
2711         NTSTATUS status;
2712
2713         status = cli_locktype(cli, fnum, offset, len, timeout,
2714                               (lock_type == READ_LOCK? 1 : 0));
2715         return status;
2716 }
2717
2718 /****************************************************************************
2719  Unlock a file.
2720 ****************************************************************************/
2721
2722 struct cli_unlock_state {
2723         uint16_t vwv[8];
2724         uint8_t data[10];
2725 };
2726
2727 static void cli_unlock_done(struct tevent_req *subreq);
2728
2729 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
2730                                 struct event_context *ev,
2731                                 struct cli_state *cli,
2732                                 uint16_t fnum,
2733                                 uint64_t offset,
2734                                 uint64_t len)
2735
2736 {
2737         struct tevent_req *req = NULL, *subreq = NULL;
2738         struct cli_unlock_state *state = NULL;
2739         uint8_t additional_flags = 0;
2740
2741         req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
2742         if (req == NULL) {
2743                 return NULL;
2744         }
2745
2746         SCVAL(state->vwv+0, 0, 0xFF);
2747         SSVAL(state->vwv+2, 0, fnum);
2748         SCVAL(state->vwv+3, 0, 0);
2749         SIVALS(state->vwv+4, 0, 0);
2750         SSVAL(state->vwv+6, 0, 1);
2751         SSVAL(state->vwv+7, 0, 0);
2752
2753         SSVAL(state->data, 0, cli_getpid(cli));
2754         SIVAL(state->data, 2, offset);
2755         SIVAL(state->data, 6, len);
2756
2757         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2758                                 8, state->vwv, 10, state->data);
2759         if (tevent_req_nomem(subreq, req)) {
2760                 return tevent_req_post(req, ev);
2761         }
2762         tevent_req_set_callback(subreq, cli_unlock_done, req);
2763         return req;
2764 }
2765
2766 static void cli_unlock_done(struct tevent_req *subreq)
2767 {
2768         struct tevent_req *req = tevent_req_callback_data(
2769                                 subreq, struct tevent_req);
2770         NTSTATUS status;
2771
2772         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2773         TALLOC_FREE(subreq);
2774         if (tevent_req_nterror(req, status)) {
2775                 return;
2776         }
2777         tevent_req_done(req);
2778 }
2779
2780 NTSTATUS cli_unlock_recv(struct tevent_req *req)
2781 {
2782         return tevent_req_simple_recv_ntstatus(req);
2783 }
2784
2785 NTSTATUS cli_unlock(struct cli_state *cli,
2786                         uint16_t fnum,
2787                         uint32_t offset,
2788                         uint32_t len)
2789 {
2790         TALLOC_CTX *frame = talloc_stackframe();
2791         struct event_context *ev;
2792         struct tevent_req *req;
2793         NTSTATUS status = NT_STATUS_OK;
2794
2795         if (smbXcli_conn_has_async_calls(cli->conn)) {
2796                 /*
2797                  * Can't use sync call while an async call is in flight
2798                  */
2799                 status = NT_STATUS_INVALID_PARAMETER;
2800                 goto fail;
2801         }
2802
2803         ev = event_context_init(frame);
2804         if (ev == NULL) {
2805                 status = NT_STATUS_NO_MEMORY;
2806                 goto fail;
2807         }
2808
2809         req = cli_unlock_send(frame, ev, cli,
2810                         fnum, offset, len);
2811         if (req == NULL) {
2812                 status = NT_STATUS_NO_MEMORY;
2813                 goto fail;
2814         }
2815
2816         if (!tevent_req_poll(req, ev)) {
2817                 status = map_nt_error_from_unix(errno);
2818                 goto fail;
2819         }
2820
2821         status = cli_unlock_recv(req);
2822
2823  fail:
2824         TALLOC_FREE(frame);
2825         return status;
2826 }
2827
2828 /****************************************************************************
2829  Lock a file with 64 bit offsets.
2830 ****************************************************************************/
2831
2832 NTSTATUS cli_lock64(struct cli_state *cli, uint16_t fnum,
2833                     uint64_t offset, uint64_t len, int timeout,
2834                     enum brl_type lock_type)
2835 {
2836         uint16_t vwv[8];
2837         uint8_t bytes[20];
2838         unsigned int set_timeout = 0;
2839         unsigned int saved_timeout = 0;
2840         int ltype;
2841         NTSTATUS status;
2842
2843         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
2844                 return cli_lock32(cli, fnum, offset, len, timeout, lock_type);
2845         }
2846
2847         ltype = (lock_type == READ_LOCK? 1 : 0);
2848         ltype |= LOCKING_ANDX_LARGE_FILES;
2849
2850         SCVAL(vwv + 0, 0, 0xff);
2851         SCVAL(vwv + 0, 1, 0);
2852         SSVAL(vwv + 1, 0, 0);
2853         SSVAL(vwv + 2, 0, fnum);
2854         SCVAL(vwv + 3, 0, ltype);
2855         SCVAL(vwv + 3, 1, 0);
2856         SIVALS(vwv + 4, 0, timeout);
2857         SSVAL(vwv + 6, 0, 0);
2858         SSVAL(vwv + 7, 0, 1);
2859
2860         SIVAL(bytes, 0, cli_getpid(cli));
2861         SOFF_T_R(bytes, 4, offset);
2862         SOFF_T_R(bytes, 12, len);
2863
2864         if (timeout != 0) {
2865                 if (timeout == -1) {
2866                         set_timeout = 0x7FFFFFFF;
2867                 } else {
2868                         set_timeout = timeout + 2*1000;
2869                 }
2870                 saved_timeout = cli_set_timeout(cli, set_timeout);
2871         }
2872
2873         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2874                          20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2875
2876         if (saved_timeout != 0) {
2877                 cli_set_timeout(cli, saved_timeout);
2878         }
2879
2880         return status;
2881 }
2882
2883 /****************************************************************************
2884  Unlock a file with 64 bit offsets.
2885 ****************************************************************************/
2886
2887 struct cli_unlock64_state {
2888         uint16_t vwv[8];
2889         uint8_t data[20];
2890 };
2891
2892 static void cli_unlock64_done(struct tevent_req *subreq);
2893
2894 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
2895                                 struct event_context *ev,
2896                                 struct cli_state *cli,
2897                                 uint16_t fnum,
2898                                 uint64_t offset,
2899                                 uint64_t len)
2900
2901 {
2902         struct tevent_req *req = NULL, *subreq = NULL;
2903         struct cli_unlock64_state *state = NULL;
2904         uint8_t additional_flags = 0;
2905
2906         req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
2907         if (req == NULL) {
2908                 return NULL;
2909         }
2910
2911         SCVAL(state->vwv+0, 0, 0xff);
2912         SSVAL(state->vwv+2, 0, fnum);
2913         SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
2914         SIVALS(state->vwv+4, 0, 0);
2915         SSVAL(state->vwv+6, 0, 1);
2916         SSVAL(state->vwv+7, 0, 0);
2917
2918         SIVAL(state->data, 0, cli_getpid(cli));
2919         SOFF_T_R(state->data, 4, offset);
2920         SOFF_T_R(state->data, 12, len);
2921
2922         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2923                                 8, state->vwv, 20, state->data);
2924         if (tevent_req_nomem(subreq, req)) {
2925                 return tevent_req_post(req, ev);
2926         }
2927         tevent_req_set_callback(subreq, cli_unlock64_done, req);
2928         return req;
2929 }
2930
2931 static void cli_unlock64_done(struct tevent_req *subreq)
2932 {
2933         struct tevent_req *req = tevent_req_callback_data(
2934                                 subreq, struct tevent_req);
2935         NTSTATUS status;
2936
2937         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2938         TALLOC_FREE(subreq);
2939         if (tevent_req_nterror(req, status)) {
2940                 return;
2941         }
2942         tevent_req_done(req);
2943 }
2944
2945 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
2946 {
2947         return tevent_req_simple_recv_ntstatus(req);
2948 }
2949
2950 NTSTATUS cli_unlock64(struct cli_state *cli,
2951                                 uint16_t fnum,
2952                                 uint64_t offset,
2953                                 uint64_t len)
2954 {
2955         TALLOC_CTX *frame = talloc_stackframe();
2956         struct event_context *ev;
2957         struct tevent_req *req;
2958         NTSTATUS status = NT_STATUS_OK;
2959
2960         if (! (smb1cli_conn_capabilities(cli->conn) & CAP_LARGE_FILES)) {
2961                 return cli_unlock(cli, fnum, offset, len);
2962         }
2963
2964         if (smbXcli_conn_has_async_calls(cli->conn)) {
2965                 /*
2966                  * Can't use sync call while an async call is in flight
2967                  */
2968                 status = NT_STATUS_INVALID_PARAMETER;
2969                 goto fail;
2970         }
2971
2972         ev = event_context_init(frame);
2973         if (ev == NULL) {
2974                 status = NT_STATUS_NO_MEMORY;
2975                 goto fail;
2976         }
2977
2978         req = cli_unlock64_send(frame, ev, cli,
2979                         fnum, offset, len);
2980         if (req == NULL) {
2981                 status = NT_STATUS_NO_MEMORY;
2982                 goto fail;
2983         }
2984
2985         if (!tevent_req_poll(req, ev)) {
2986                 status = map_nt_error_from_unix(errno);
2987                 goto fail;
2988         }
2989
2990         status = cli_unlock64_recv(req);
2991
2992  fail:
2993         TALLOC_FREE(frame);
2994         return status;
2995 }
2996
2997 /****************************************************************************
2998  Get/unlock a POSIX lock on a file - internal function.
2999 ****************************************************************************/
3000
3001 struct posix_lock_state {
3002         uint16_t setup;
3003         uint8_t param[4];
3004         uint8_t data[POSIX_LOCK_DATA_SIZE];
3005 };
3006
3007 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
3008 {
3009         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
3010                                          NULL, 0, NULL, NULL, 0, NULL);
3011         tevent_req_simple_finish_ntstatus(subreq, status);
3012 }
3013
3014 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
3015                                         struct event_context *ev,
3016                                         struct cli_state *cli,
3017                                         uint16_t fnum,
3018                                         uint64_t offset,
3019                                         uint64_t len,
3020                                         bool wait_lock,
3021                                         enum brl_type lock_type)
3022 {
3023         struct tevent_req *req = NULL, *subreq = NULL;
3024         struct posix_lock_state *state = NULL;
3025
3026         req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
3027         if (req == NULL) {
3028                 return NULL;
3029         }
3030
3031         /* Setup setup word. */
3032         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3033
3034         /* Setup param array. */
3035         SSVAL(&state->param, 0, fnum);
3036         SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3037
3038         /* Setup data array. */
3039         switch (lock_type) {
3040                 case READ_LOCK:
3041                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3042                                 POSIX_LOCK_TYPE_READ);
3043                         break;
3044                 case WRITE_LOCK:
3045                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3046                                 POSIX_LOCK_TYPE_WRITE);
3047                         break;
3048                 case UNLOCK_LOCK:
3049                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3050                                 POSIX_LOCK_TYPE_UNLOCK);
3051                         break;
3052                 default:
3053                         return NULL;
3054         }
3055
3056         if (wait_lock) {
3057                 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3058                                 POSIX_LOCK_FLAG_WAIT);
3059         } else {
3060                 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3061                                 POSIX_LOCK_FLAG_NOWAIT);
3062         }
3063
3064         SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
3065         SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3066         SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3067
3068         subreq = cli_trans_send(state,                  /* mem ctx. */
3069                                 ev,                     /* event ctx. */
3070                                 cli,                    /* cli_state. */
3071                                 SMBtrans2,              /* cmd. */
3072                                 NULL,                   /* pipe name. */
3073                                 -1,                     /* fid. */
3074                                 0,                      /* function. */
3075                                 0,                      /* flags. */
3076                                 &state->setup,          /* setup. */
3077                                 1,                      /* num setup uint16_t words. */
3078                                 0,                      /* max returned setup. */
3079                                 state->param,           /* param. */
3080                                 4,                      /* num param. */
3081                                 2,                      /* max returned param. */
3082                                 state->data,            /* data. */
3083                                 POSIX_LOCK_DATA_SIZE,   /* num data. */
3084                                 0);                     /* max returned data. */
3085
3086         if (tevent_req_nomem(subreq, req)) {
3087                 return tevent_req_post(req, ev);
3088         }
3089         tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3090         return req;
3091 }
3092
3093 /****************************************************************************
3094  POSIX Lock a file.
3095 ****************************************************************************/
3096
3097 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3098                                         struct event_context *ev,
3099                                         struct cli_state *cli,
3100                                         uint16_t fnum,
3101                                         uint64_t offset,
3102                                         uint64_t len,
3103                                         bool wait_lock,
3104                                         enum brl_type lock_type)
3105 {
3106         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3107                                         wait_lock, lock_type);
3108 }
3109
3110 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3111 {
3112         return tevent_req_simple_recv_ntstatus(req);
3113 }
3114
3115 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3116                         uint64_t offset, uint64_t len,
3117                         bool wait_lock, enum brl_type lock_type)
3118 {
3119         TALLOC_CTX *frame = talloc_stackframe();
3120         struct event_context *ev = NULL;
3121         struct tevent_req *req = NULL;
3122         NTSTATUS status = NT_STATUS_OK;
3123
3124         if (smbXcli_conn_has_async_calls(cli->conn)) {
3125                 /*
3126                  * Can't use sync call while an async call is in flight
3127                  */
3128                 status = NT_STATUS_INVALID_PARAMETER;
3129                 goto fail;
3130         }
3131
3132         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3133                 status = NT_STATUS_INVALID_PARAMETER;
3134                 goto fail;
3135         }
3136
3137         ev = event_context_init(frame);
3138         if (ev == NULL) {
3139                 status = NT_STATUS_NO_MEMORY;
3140                 goto fail;
3141         }
3142
3143         req = cli_posix_lock_send(frame,
3144                                 ev,
3145                                 cli,
3146                                 fnum,
3147                                 offset,
3148                                 len,
3149                                 wait_lock,
3150                                 lock_type);
3151         if (req == NULL) {
3152                 status = NT_STATUS_NO_MEMORY;
3153                 goto fail;
3154         }
3155
3156         if (!tevent_req_poll(req, ev)) {
3157                 status = map_nt_error_from_unix(errno);
3158                 goto fail;
3159         }
3160
3161         status = cli_posix_lock_recv(req);
3162
3163  fail:
3164         TALLOC_FREE(frame);
3165         return status;
3166 }
3167
3168 /****************************************************************************
3169  POSIX Unlock a file.
3170 ****************************************************************************/
3171
3172 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3173                                         struct event_context *ev,
3174                                         struct cli_state *cli,
3175                                         uint16_t fnum,
3176                                         uint64_t offset,
3177                                         uint64_t len)
3178 {
3179         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3180                                         false, UNLOCK_LOCK);
3181 }
3182
3183 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3184 {
3185         return tevent_req_simple_recv_ntstatus(req);
3186 }
3187
3188 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3189 {
3190         TALLOC_CTX *frame = talloc_stackframe();
3191         struct event_context *ev = NULL;
3192         struct tevent_req *req = NULL;
3193         NTSTATUS status = NT_STATUS_OK;
3194
3195         if (smbXcli_conn_has_async_calls(cli->conn)) {
3196                 /*
3197                  * Can't use sync call while an async call is in flight
3198                  */
3199                 status = NT_STATUS_INVALID_PARAMETER;
3200                 goto fail;
3201         }
3202
3203         ev = event_context_init(frame);
3204         if (ev == NULL) {
3205                 status = NT_STATUS_NO_MEMORY;
3206                 goto fail;
3207         }
3208
3209         req = cli_posix_unlock_send(frame,
3210                                 ev,
3211                                 cli,
3212                                 fnum,
3213                                 offset,
3214                                 len);
3215         if (req == NULL) {
3216                 status = NT_STATUS_NO_MEMORY;
3217                 goto fail;
3218         }
3219
3220         if (!tevent_req_poll(req, ev)) {
3221                 status = map_nt_error_from_unix(errno);
3222                 goto fail;
3223         }
3224
3225         status = cli_posix_unlock_recv(req);
3226
3227  fail:
3228         TALLOC_FREE(frame);
3229         return status;
3230 }
3231
3232 /****************************************************************************
3233  Do a SMBgetattrE call.
3234 ****************************************************************************/
3235
3236 static void cli_getattrE_done(struct tevent_req *subreq);
3237
3238 struct cli_getattrE_state {
3239         uint16_t vwv[1];
3240         int zone_offset;
3241         uint16_t attr;
3242         off_t size;
3243         time_t change_time;
3244         time_t access_time;
3245         time_t write_time;
3246 };
3247
3248 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3249                                 struct event_context *ev,
3250                                 struct cli_state *cli,
3251                                 uint16_t fnum)
3252 {
3253         struct tevent_req *req = NULL, *subreq = NULL;
3254         struct cli_getattrE_state *state = NULL;
3255         uint8_t additional_flags = 0;
3256
3257         req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3258         if (req == NULL) {
3259                 return NULL;
3260         }
3261
3262         state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3263         SSVAL(state->vwv+0,0,fnum);
3264
3265         subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
3266                               1, state->vwv, 0, NULL);
3267         if (tevent_req_nomem(subreq, req)) {
3268                 return tevent_req_post(req, ev);
3269         }
3270         tevent_req_set_callback(subreq, cli_getattrE_done, req);
3271         return req;
3272 }
3273
3274 static void cli_getattrE_done(struct tevent_req *subreq)
3275 {
3276         struct tevent_req *req = tevent_req_callback_data(
3277                 subreq, struct tevent_req);
3278         struct cli_getattrE_state *state = tevent_req_data(
3279                 req, struct cli_getattrE_state);
3280         uint8_t wct;
3281         uint16_t *vwv = NULL;
3282         uint8_t *inbuf;
3283         NTSTATUS status;
3284
3285         status = cli_smb_recv(subreq, state, &inbuf, 11, &wct, &vwv,
3286                               NULL, NULL);
3287         TALLOC_FREE(subreq);
3288         if (tevent_req_nterror(req, status)) {
3289                 return;
3290         }
3291
3292         state->size = (off_t)IVAL(vwv+6,0);
3293         state->attr = SVAL(vwv+10,0);
3294         state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3295         state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3296         state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3297
3298         tevent_req_done(req);
3299 }
3300
3301 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3302                         uint16_t *attr,
3303                         off_t *size,
3304                         time_t *change_time,
3305                         time_t *access_time,
3306                         time_t *write_time)
3307 {
3308         struct cli_getattrE_state *state = tevent_req_data(
3309                                 req, struct cli_getattrE_state);
3310         NTSTATUS status;
3311
3312         if (tevent_req_is_nterror(req, &status)) {
3313                 return status;
3314         }
3315         if (attr) {
3316                 *attr = state->attr;
3317         }
3318         if (size) {
3319                 *size = state->size;
3320         }
3321         if (change_time) {
3322                 *change_time = state->change_time;
3323         }
3324         if (access_time) {
3325                 *access_time = state->access_time;
3326         }
3327         if (write_time) {
3328                 *write_time = state->write_time;
3329         }
3330         return NT_STATUS_OK;
3331 }
3332
3333 NTSTATUS cli_getattrE(struct cli_state *cli,
3334                         uint16_t fnum,
3335                         uint16_t *attr,
3336                         off_t *size,
3337                         time_t *change_time,
3338                         time_t *access_time,
3339                         time_t *write_time)
3340 {
3341         TALLOC_CTX *frame = talloc_stackframe();
3342         struct event_context *ev = NULL;
3343         struct tevent_req *req = NULL;
3344         NTSTATUS status = NT_STATUS_OK;
3345
3346         if (smbXcli_conn_has_async_calls(cli->conn)) {
3347                 /*
3348                  * Can't use sync call while an async call is in flight
3349                  */
3350                 status = NT_STATUS_INVALID_PARAMETER;
3351                 goto fail;
3352         }
3353
3354         ev = event_context_init(frame);
3355         if (ev == NULL) {
3356                 status = NT_STATUS_NO_MEMORY;
3357                 goto fail;
3358         }
3359
3360         req = cli_getattrE_send(frame, ev, cli, fnum);
3361         if (req == NULL) {
3362                 status = NT_STATUS_NO_MEMORY;
3363                 goto fail;
3364         }
3365
3366         if (!tevent_req_poll(req, ev)) {
3367                 status = map_nt_error_from_unix(errno);
3368                 goto fail;
3369         }
3370
3371         status = cli_getattrE_recv(req,
3372                                         attr,
3373                                         size,
3374                                         change_time,
3375                                         access_time,
3376                                         write_time);
3377
3378  fail:
3379         TALLOC_FREE(frame);
3380         return status;
3381 }
3382
3383 /****************************************************************************
3384  Do a SMBgetatr call
3385 ****************************************************************************/
3386
3387 static void cli_getatr_done(struct tevent_req *subreq);
3388
3389 struct cli_getatr_state {
3390         int zone_offset;
3391         uint16_t attr;
3392         off_t size;
3393         time_t write_time;
3394 };
3395
3396 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3397                                 struct event_context *ev,
3398                                 struct cli_state *cli,
3399                                 const char *fname)
3400 {
3401         struct tevent_req *req = NULL, *subreq = NULL;
3402         struct cli_getatr_state *state = NULL;
3403         uint8_t additional_flags = 0;
3404         uint8_t *bytes = NULL;
3405
3406         req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3407         if (req == NULL) {
3408                 return NULL;
3409         }
3410
3411         state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
3412
3413         bytes = talloc_array(state, uint8_t, 1);
3414         if (tevent_req_nomem(bytes, req)) {
3415                 return tevent_req_post(req, ev);
3416         }
3417         bytes[0] = 4;
3418         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3419                                    strlen(fname)+1, NULL);
3420
3421         if (tevent_req_nomem(bytes, req)) {
3422                 return tevent_req_post(req, ev);
3423         }
3424
3425         subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3426                               0, NULL, talloc_get_size(bytes), bytes);
3427         if (tevent_req_nomem(subreq, req)) {
3428                 return tevent_req_post(req, ev);
3429         }
3430         tevent_req_set_callback(subreq, cli_getatr_done, req);
3431         return req;
3432 }
3433
3434 static void cli_getatr_done(struct tevent_req *subreq)
3435 {
3436         struct tevent_req *req = tevent_req_callback_data(
3437                 subreq, struct tevent_req);
3438         struct cli_getatr_state *state = tevent_req_data(
3439                 req, struct cli_getatr_state);
3440         uint8_t wct;
3441         uint16_t *vwv = NULL;
3442         uint8_t *inbuf;
3443         NTSTATUS status;
3444
3445         status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3446                               NULL);
3447         TALLOC_FREE(subreq);
3448         if (tevent_req_nterror(req, status)) {
3449                 return;
3450         }
3451
3452         state->attr = SVAL(vwv+0,0);
3453         state->size = (off_t)IVAL(vwv+3,0);
3454         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3455
3456         tevent_req_done(req);
3457 }
3458
3459 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3460                         uint16_t *attr,
3461                         off_t *size,
3462                         time_t *write_time)
3463 {
3464         struct cli_getatr_state *state = tevent_req_data(
3465                                 req, struct cli_getatr_state);
3466         NTSTATUS status;
3467
3468         if (tevent_req_is_nterror(req, &status)) {
3469                 return status;
3470         }
3471         if (attr) {
3472                 *attr = state->attr;
3473         }
3474         if (size) {
3475                 *size = state->size;
3476         }
3477         if (write_time) {
3478                 *write_time = state->write_time;
3479         }
3480         return NT_STATUS_OK;
3481 }
3482
3483 NTSTATUS cli_getatr(struct cli_state *cli,
3484                         const char *fname,
3485                         uint16_t *attr,
3486                         off_t *size,
3487                         time_t *write_time)
3488 {
3489         TALLOC_CTX *frame = talloc_stackframe();
3490         struct event_context *ev = NULL;
3491         struct tevent_req *req = NULL;
3492         NTSTATUS status = NT_STATUS_OK;
3493
3494         if (smbXcli_conn_has_async_calls(cli->conn)) {
3495                 /*
3496                  * Can't use sync call while an async call is in flight
3497                  */
3498                 status = NT_STATUS_INVALID_PARAMETER;
3499                 goto fail;
3500         }
3501
3502         ev = event_context_init(frame);
3503         if (ev == NULL) {
3504                 status = NT_STATUS_NO_MEMORY;
3505                 goto fail;
3506         }
3507
3508         req = cli_getatr_send(frame, ev, cli, fname);
3509         if (req == NULL) {
3510                 status = NT_STATUS_NO_MEMORY;
3511                 goto fail;
3512         }
3513
3514         if (!tevent_req_poll(req, ev)) {
3515                 status = map_nt_error_from_unix(errno);
3516                 goto fail;
3517         }
3518
3519         status = cli_getatr_recv(req,
3520                                 attr,
3521                                 size,
3522                                 write_time);
3523
3524  fail:
3525         TALLOC_FREE(frame);
3526         return status;
3527 }
3528
3529 /****************************************************************************
3530  Do a SMBsetattrE call.
3531 ****************************************************************************/
3532
3533 static void cli_setattrE_done(struct tevent_req *subreq);
3534
3535 struct cli_setattrE_state {
3536         uint16_t vwv[7];
3537 };
3538
3539 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3540                                 struct event_context *ev,
3541                                 struct cli_state *cli,
3542                                 uint16_t fnum,
3543                                 time_t change_time,
3544                                 time_t access_time,
3545                                 time_t write_time)
3546 {
3547         struct tevent_req *req = NULL, *subreq = NULL;
3548         struct cli_setattrE_state *state = NULL;
3549         uint8_t additional_flags = 0;
3550
3551         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3552         if (req == NULL) {
3553                 return NULL;
3554         }
3555
3556         SSVAL(state->vwv+0, 0, fnum);
3557         push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
3558                        smb1cli_conn_server_time_zone(cli->conn));
3559         push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
3560                        smb1cli_conn_server_time_zone(cli->conn));
3561         push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
3562                        smb1cli_conn_server_time_zone(cli->conn));
3563
3564         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3565                               7, state->vwv, 0, NULL);
3566         if (tevent_req_nomem(subreq, req)) {
3567                 return tevent_req_post(req, ev);
3568         }
3569         tevent_req_set_callback(subreq, cli_setattrE_done, req);
3570         return req;
3571 }
3572
3573 static void cli_setattrE_done(struct tevent_req *subreq)
3574 {
3575         struct tevent_req *req = tevent_req_callback_data(
3576                 subreq, struct tevent_req);
3577         NTSTATUS status;
3578
3579         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3580         TALLOC_FREE(subreq);
3581         if (tevent_req_nterror(req, status)) {
3582                 return;
3583         }
3584         tevent_req_done(req);
3585 }
3586
3587 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3588 {
3589         return tevent_req_simple_recv_ntstatus(req);
3590 }
3591
3592 NTSTATUS cli_setattrE(struct cli_state *cli,
3593                         uint16_t fnum,
3594                         time_t change_time,
3595                         time_t access_time,
3596                         time_t write_time)
3597 {
3598         TALLOC_CTX *frame = talloc_stackframe();
3599         struct event_context *ev = NULL;
3600         struct tevent_req *req = NULL;
3601         NTSTATUS status = NT_STATUS_OK;
3602
3603         if (smbXcli_conn_has_async_calls(cli->conn)) {
3604                 /*
3605                  * Can't use sync call while an async call is in flight
3606                  */
3607                 status = NT_STATUS_INVALID_PARAMETER;
3608                 goto fail;
3609         }
3610
3611         ev = event_context_init(frame);
3612         if (ev == NULL) {
3613                 status = NT_STATUS_NO_MEMORY;
3614                 goto fail;
3615         }
3616
3617         req = cli_setattrE_send(frame, ev,
3618                         cli,
3619                         fnum,
3620                         change_time,
3621                         access_time,
3622                         write_time);
3623
3624         if (req == NULL) {
3625                 status = NT_STATUS_NO_MEMORY;
3626                 goto fail;
3627         }
3628
3629         if (!tevent_req_poll(req, ev)) {
3630                 status = map_nt_error_from_unix(errno);
3631                 goto fail;
3632         }
3633
3634         status = cli_setattrE_recv(req);
3635
3636  fail:
3637         TALLOC_FREE(frame);
3638         return status;
3639 }
3640
3641 /****************************************************************************
3642  Do a SMBsetatr call.
3643 ****************************************************************************/
3644
3645 static void cli_setatr_done(struct tevent_req *subreq);
3646
3647 struct cli_setatr_state {
3648         uint16_t vwv[8];
3649 };
3650
3651 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3652                                 struct event_context *ev,
3653                                 struct cli_state *cli,
3654                                 const char *fname,
3655                                 uint16_t attr,
3656                                 time_t mtime)
3657 {
3658         struct tevent_req *req = NULL, *subreq = NULL;
3659         struct cli_setatr_state *state = NULL;
3660         uint8_t additional_flags = 0;
3661         uint8_t *bytes = NULL;
3662
3663         req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3664         if (req == NULL) {
3665                 return NULL;
3666         }
3667
3668         SSVAL(state->vwv+0, 0, attr);
3669         push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
3670
3671         bytes = talloc_array(state, uint8_t, 1);
3672         if (tevent_req_nomem(bytes, req)) {
3673                 return tevent_req_post(req, ev);
3674         }
3675         bytes[0] = 4;
3676         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3677                                    strlen(fname)+1, NULL);
3678         if (tevent_req_nomem(bytes, req)) {
3679                 return tevent_req_post(req, ev);
3680         }
3681         bytes = talloc_realloc(state, bytes, uint8_t,
3682                         talloc_get_size(bytes)+1);
3683         if (tevent_req_nomem(bytes, req)) {
3684                 return tevent_req_post(req, ev);
3685         }
3686
3687         bytes[talloc_get_size(bytes)-1] = 4;
3688         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
3689                                    1, NULL);
3690         if (tevent_req_nomem(bytes, req)) {
3691                 return tevent_req_post(req, ev);
3692         }
3693
3694         subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3695                               8, state->vwv, talloc_get_size(bytes), bytes);
3696         if (tevent_req_nomem(subreq, req)) {
3697                 return tevent_req_post(req, ev);
3698         }
3699         tevent_req_set_callback(subreq, cli_setatr_done, req);
3700         return req;
3701 }
3702
3703 static void cli_setatr_done(struct tevent_req *subreq)
3704 {
3705         struct tevent_req *req = tevent_req_callback_data(
3706                 subreq, struct tevent_req);
3707         NTSTATUS status;
3708
3709         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3710         TALLOC_FREE(subreq);
3711         if (tevent_req_nterror(req, status)) {
3712                 return;
3713         }
3714         tevent_req_done(req);
3715 }
3716
3717 NTSTATUS cli_setatr_recv(struct tevent_req *req)
3718 {
3719         return tevent_req_simple_recv_ntstatus(req);
3720 }
3721
3722 NTSTATUS cli_setatr(struct cli_state *cli,
3723                 const char *fname,
3724                 uint16_t attr,
3725                 time_t mtime)
3726 {
3727         TALLOC_CTX *frame = talloc_stackframe();
3728         struct event_context *ev = NULL;
3729         struct tevent_req *req = NULL;
3730         NTSTATUS status = NT_STATUS_OK;
3731
3732         if (smbXcli_conn_has_async_calls(cli->conn)) {
3733                 /*
3734                  * Can't use sync call while an async call is in flight
3735                  */
3736                 status = NT_STATUS_INVALID_PARAMETER;
3737                 goto fail;
3738         }
3739
3740         ev = event_context_init(frame);
3741         if (ev == NULL) {
3742                 status = NT_STATUS_NO_MEMORY;
3743                 goto fail;
3744         }
3745
3746         req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
3747         if (req == NULL) {
3748                 status = NT_STATUS_NO_MEMORY;
3749                 goto fail;
3750         }
3751
3752         if (!tevent_req_poll(req, ev)) {
3753                 status = map_nt_error_from_unix(errno);
3754                 goto fail;
3755         }
3756
3757         status = cli_setatr_recv(req);
3758
3759  fail:
3760         TALLOC_FREE(frame);
3761         return status;
3762 }
3763
3764 /****************************************************************************
3765  Check for existance of a dir.
3766 ****************************************************************************/
3767
3768 static void cli_chkpath_done(struct tevent_req *subreq);
3769
3770 struct cli_chkpath_state {
3771         int dummy;
3772 };
3773
3774 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
3775                                   struct event_context *ev,
3776                                   struct cli_state *cli,
3777                                   const char *fname)
3778 {
3779         struct tevent_req *req = NULL, *subreq = NULL;
3780         struct cli_chkpath_state *state = NULL;
3781         uint8_t additional_flags = 0;
3782         uint8_t *bytes = NULL;
3783
3784         req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
3785         if (req == NULL) {
3786                 return NULL;
3787         }
3788
3789         bytes = talloc_array(state, uint8_t, 1);
3790         if (tevent_req_nomem(bytes, req)) {
3791                 return tevent_req_post(req, ev);
3792         }
3793         bytes[0] = 4;
3794         bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), fname,
3795                                    strlen(fname)+1, NULL);
3796
3797         if (tevent_req_nomem(bytes, req)) {
3798                 return tevent_req_post(req, ev);
3799         }
3800
3801         subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
3802                               0, NULL, talloc_get_size(bytes), bytes);
3803         if (tevent_req_nomem(subreq, req)) {
3804                 return tevent_req_post(req, ev);
3805         }
3806         tevent_req_set_callback(subreq, cli_chkpath_done, req);
3807         return req;
3808 }
3809
3810 static void cli_chkpath_done(struct tevent_req *subreq)
3811 {
3812         struct tevent_req *req = tevent_req_callback_data(
3813                 subreq, struct tevent_req);
3814         NTSTATUS status;
3815
3816         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3817         TALLOC_FREE(subreq);
3818         if (tevent_req_nterror(req, status)) {
3819                 return;
3820         }
3821         tevent_req_done(req);
3822 }
3823
3824 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
3825 {
3826         return tevent_req_simple_recv_ntstatus(req);
3827 }
3828
3829 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
3830 {
3831         TALLOC_CTX *frame = talloc_stackframe();
3832         struct event_context *ev = NULL;
3833         struct tevent_req *req = NULL;
3834         char *path2 = NULL;
3835         NTSTATUS status = NT_STATUS_OK;
3836
3837         if (smbXcli_conn_has_async_calls(cli->conn)) {
3838                 /*