s3-talloc Change TALLOC_ARRAY() to talloc_array()
[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
30 /***********************************************************
31  Common function for pushing stings, used by smb_bytes_push_str()
32  and trans_bytes_push_str(). Only difference is the align_odd
33  parameter setting.
34 ***********************************************************/
35
36 static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
37                                 const char *str, size_t str_len,
38                                 bool align_odd,
39                                 size_t *pconverted_size)
40 {
41         size_t buflen;
42         char *converted;
43         size_t converted_size;
44
45         if (buf == NULL) {
46                 return NULL;
47         }
48
49         buflen = talloc_get_size(buf);
50
51         if (align_odd && ucs2 && (buflen % 2 == 0)) {
52                 /*
53                  * We're pushing into an SMB buffer, align odd
54                  */
55                 buf = talloc_realloc(NULL, buf, uint8_t, buflen + 1);
56                 if (buf == NULL) {
57                         return NULL;
58                 }
59                 buf[buflen] = '\0';
60                 buflen += 1;
61         }
62
63         if (!convert_string_talloc(talloc_tos(), CH_UNIX,
64                                    ucs2 ? CH_UTF16LE : CH_DOS,
65                                    str, str_len, &converted,
66                                    &converted_size)) {
67                 return NULL;
68         }
69
70         buf = talloc_realloc(NULL, buf, uint8_t,
71                                    buflen + converted_size);
72         if (buf == NULL) {
73                 TALLOC_FREE(converted);
74                 return NULL;
75         }
76
77         memcpy(buf + buflen, converted, converted_size);
78
79         TALLOC_FREE(converted);
80
81         if (pconverted_size) {
82                 *pconverted_size = converted_size;
83         }
84
85         return buf;
86 }
87
88 /***********************************************************
89  Push a string into an SMB buffer, with odd byte alignment
90  if it's a UCS2 string.
91 ***********************************************************/
92
93 uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
94                             const char *str, size_t str_len,
95                             size_t *pconverted_size)
96 {
97         return internal_bytes_push_str(buf, ucs2, str, str_len,
98                         true, pconverted_size);
99 }
100
101 uint8_t *smb_bytes_push_bytes(uint8_t *buf, uint8_t prefix,
102                               const uint8_t *bytes, size_t num_bytes)
103 {
104         size_t buflen;
105
106         if (buf == NULL) {
107                 return NULL;
108         }
109         buflen = talloc_get_size(buf);
110
111         buf = talloc_realloc(NULL, buf, uint8_t,
112                                    buflen + 1 + num_bytes);
113         if (buf == NULL) {
114                 return NULL;
115         }
116         buf[buflen] = prefix;
117         memcpy(&buf[buflen+1], bytes, num_bytes);
118         return buf;
119 }
120
121 /***********************************************************
122  Same as smb_bytes_push_str(), but without the odd byte
123  align for ucs2 (we're pushing into a param or data block).
124  static for now, although this will probably change when
125  other modules use async trans calls.
126 ***********************************************************/
127
128 static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
129                             const char *str, size_t str_len,
130                             size_t *pconverted_size)
131 {
132         return internal_bytes_push_str(buf, ucs2, str, str_len,
133                         false, pconverted_size);
134 }
135
136 struct cli_setpathinfo_state {
137         uint16_t setup;
138         uint8_t *param;
139 };
140
141 static void cli_setpathinfo_done(struct tevent_req *subreq);
142
143 struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
144                                         struct tevent_context *ev,
145                                         struct cli_state *cli,
146                                         uint16_t level,
147                                         const char *path,
148                                         uint8_t *data,
149                                         size_t data_len)
150 {
151         struct tevent_req *req, *subreq;
152         struct cli_setpathinfo_state *state;
153
154         req = tevent_req_create(mem_ctx, &state,
155                                 struct cli_setpathinfo_state);
156         if (req == NULL) {
157                 return NULL;
158         }
159
160         /* Setup setup word. */
161         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
162
163         /* Setup param array. */
164         state->param = TALLOC_ZERO_ARRAY(state, uint8_t, 6);
165         if (tevent_req_nomem(state->param, req)) {
166                 return tevent_req_post(req, ev);
167         }
168         SSVAL(state->param, 0, level);
169
170         state->param = trans2_bytes_push_str(
171                 state->param, cli_ucs2(cli), path, strlen(path)+1, NULL);
172         if (tevent_req_nomem(state->param, req)) {
173                 return tevent_req_post(req, ev);
174         }
175
176         subreq = cli_trans_send(
177                 state,                  /* mem ctx. */
178                 ev,                     /* event ctx. */
179                 cli,                    /* cli_state. */
180                 SMBtrans2,              /* cmd. */
181                 NULL,                   /* pipe name. */
182                 -1,                     /* fid. */
183                 0,                      /* function. */
184                 0,                      /* flags. */
185                 &state->setup,          /* setup. */
186                 1,                      /* num setup uint16_t words. */
187                 0,                      /* max returned setup. */
188                 state->param,           /* param. */
189                 talloc_get_size(state->param),  /* num param. */
190                 2,                      /* max returned param. */
191                 data,                   /* data. */
192                 data_len,               /* num data. */
193                 0);                     /* max returned data. */
194
195         if (tevent_req_nomem(subreq, req)) {
196                 return tevent_req_post(req, ev);
197         }
198         tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
199         return req;
200 }
201
202 static void cli_setpathinfo_done(struct tevent_req *subreq)
203 {
204         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
205                                          NULL, 0, NULL, NULL, 0, NULL);
206         tevent_req_simple_finish_ntstatus(subreq, status);
207 }
208
209 NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
210 {
211         return tevent_req_simple_recv_ntstatus(req);
212 }
213
214 NTSTATUS cli_setpathinfo(struct cli_state *cli,
215                          uint16_t level,
216                          const char *path,
217                          uint8_t *data,
218                          size_t data_len)
219 {
220         TALLOC_CTX *frame = talloc_stackframe();
221         struct tevent_context *ev;
222         struct tevent_req *req;
223         NTSTATUS status = NT_STATUS_NO_MEMORY;
224
225         if (cli_has_async_calls(cli)) {
226                 /*
227                  * Can't use sync call while an async call is in flight
228                  */
229                 status = NT_STATUS_INVALID_PARAMETER;
230                 goto fail;
231         }
232         ev = tevent_context_init(frame);
233         if (ev == NULL) {
234                 goto fail;
235         }
236         req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
237         if (req == NULL) {
238                 goto fail;
239         }
240         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
241                 goto fail;
242         }
243         status = cli_setpathinfo_recv(req);
244  fail:
245         TALLOC_FREE(frame);
246         return status;
247 }
248
249 /****************************************************************************
250  Hard/Symlink a file (UNIX extensions).
251  Creates new name (sym)linked to oldname.
252 ****************************************************************************/
253
254 struct cli_posix_link_internal_state {
255         uint8_t *data;
256 };
257
258 static void cli_posix_link_internal_done(struct tevent_req *subreq);
259
260 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
261                                         struct event_context *ev,
262                                         struct cli_state *cli,
263                                         uint16_t level,
264                                         const char *oldname,
265                                         const char *newname)
266 {
267         struct tevent_req *req = NULL, *subreq = NULL;
268         struct cli_posix_link_internal_state *state = NULL;
269
270         req = tevent_req_create(mem_ctx, &state,
271                                 struct cli_posix_link_internal_state);
272         if (req == NULL) {
273                 return NULL;
274         }
275
276         /* Setup data array. */
277         state->data = talloc_array(state, uint8_t, 0);
278         if (tevent_req_nomem(state->data, req)) {
279                 return tevent_req_post(req, ev);
280         }
281         state->data = trans2_bytes_push_str(
282                 state->data, cli_ucs2(cli), oldname, strlen(oldname)+1, NULL);
283
284         subreq = cli_setpathinfo_send(
285                 state, ev, cli, level, newname,
286                 state->data, talloc_get_size(state->data));
287         if (tevent_req_nomem(subreq, req)) {
288                 return tevent_req_post(req, ev);
289         }
290         tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
291         return req;
292 }
293
294 static void cli_posix_link_internal_done(struct tevent_req *subreq)
295 {
296         NTSTATUS status = cli_setpathinfo_recv(subreq);
297         tevent_req_simple_finish_ntstatus(subreq, status);
298 }
299
300 /****************************************************************************
301  Symlink a file (UNIX extensions).
302 ****************************************************************************/
303
304 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
305                                         struct event_context *ev,
306                                         struct cli_state *cli,
307                                         const char *oldname,
308                                         const char *newname)
309 {
310         return cli_posix_link_internal_send(
311                 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, oldname, newname);
312 }
313
314 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
315 {
316         return tevent_req_simple_recv_ntstatus(req);
317 }
318
319 NTSTATUS cli_posix_symlink(struct cli_state *cli,
320                         const char *oldname,
321                         const char *newname)
322 {
323         TALLOC_CTX *frame = talloc_stackframe();
324         struct event_context *ev = NULL;
325         struct tevent_req *req = NULL;
326         NTSTATUS status = NT_STATUS_OK;
327
328         if (cli_has_async_calls(cli)) {
329                 /*
330                  * Can't use sync call while an async call is in flight
331                  */
332                 status = NT_STATUS_INVALID_PARAMETER;
333                 goto fail;
334         }
335
336         ev = event_context_init(frame);
337         if (ev == NULL) {
338                 status = NT_STATUS_NO_MEMORY;
339                 goto fail;
340         }
341
342         req = cli_posix_symlink_send(frame,
343                                 ev,
344                                 cli,
345                                 oldname,
346                                 newname);
347         if (req == NULL) {
348                 status = NT_STATUS_NO_MEMORY;
349                 goto fail;
350         }
351
352         if (!tevent_req_poll(req, ev)) {
353                 status = map_nt_error_from_unix(errno);
354                 goto fail;
355         }
356
357         status = cli_posix_symlink_recv(req);
358
359  fail:
360         TALLOC_FREE(frame);
361         return status;
362 }
363
364 /****************************************************************************
365  Read a POSIX symlink.
366 ****************************************************************************/
367
368 struct readlink_state {
369         uint8_t *data;
370         uint32_t num_data;
371 };
372
373 static void cli_posix_readlink_done(struct tevent_req *subreq);
374
375 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
376                                         struct event_context *ev,
377                                         struct cli_state *cli,
378                                         const char *fname,
379                                         size_t len)
380 {
381         struct tevent_req *req = NULL, *subreq = NULL;
382         struct readlink_state *state = NULL;
383         uint32_t maxbytelen = (uint32_t)(cli_ucs2(cli) ? len*3 : len);
384
385         req = tevent_req_create(mem_ctx, &state, struct readlink_state);
386         if (req == NULL) {
387                 return NULL;
388         }
389
390         /*
391          * Len is in bytes, we need it in UCS2 units.
392          */
393         if ((2*len < len) || (maxbytelen < len)) {
394                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
395                 return tevent_req_post(req, ev);
396         }
397
398         subreq = cli_qpathinfo_send(state, ev, cli, fname,
399                                     SMB_QUERY_FILE_UNIX_LINK, 1, maxbytelen);
400         if (tevent_req_nomem(subreq, req)) {
401                 return tevent_req_post(req, ev);
402         }
403         tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
404         return req;
405 }
406
407 static void cli_posix_readlink_done(struct tevent_req *subreq)
408 {
409         struct tevent_req *req = tevent_req_callback_data(
410                 subreq, struct tevent_req);
411         struct readlink_state *state = tevent_req_data(
412                 req, struct readlink_state);
413         NTSTATUS status;
414
415         status = cli_qpathinfo_recv(subreq, state, &state->data,
416                                     &state->num_data);
417         TALLOC_FREE(subreq);
418         if (tevent_req_nterror(req, status)) {
419                 return;
420         }
421         /*
422          * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
423          */
424         if (state->data[state->num_data-1] != '\0') {
425                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
426                 return;
427         }
428         tevent_req_done(req);
429 }
430
431 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
432                                 char *retpath, size_t len)
433 {
434         NTSTATUS status;
435         char *converted = NULL;
436         size_t converted_size = 0;
437         struct readlink_state *state = tevent_req_data(req, struct readlink_state);
438
439         if (tevent_req_is_nterror(req, &status)) {
440                 return status;
441         }
442         /* The returned data is a pushed string, not raw data. */
443         if (!convert_string_talloc(state,
444                                 cli_ucs2(cli) ? CH_UTF16LE : CH_DOS, 
445                                 CH_UNIX,
446                                 state->data,
447                                 state->num_data,
448                                 &converted,
449                                 &converted_size)) {
450                 return NT_STATUS_NO_MEMORY;
451         }
452
453         len = MIN(len,converted_size);
454         if (len == 0) {
455                 return NT_STATUS_DATA_ERROR;
456         }
457         memcpy(retpath, converted, len);
458         return NT_STATUS_OK;
459 }
460
461 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
462                                 char *linkpath, size_t len)
463 {
464         TALLOC_CTX *frame = talloc_stackframe();
465         struct event_context *ev = NULL;
466         struct tevent_req *req = NULL;
467         NTSTATUS status = NT_STATUS_OK;
468
469         if (cli_has_async_calls(cli)) {
470                 /*
471                  * Can't use sync call while an async call is in flight
472                  */
473                 status = NT_STATUS_INVALID_PARAMETER;
474                 goto fail;
475         }
476
477         ev = event_context_init(frame);
478         if (ev == NULL) {
479                 status = NT_STATUS_NO_MEMORY;
480                 goto fail;
481         }
482
483         req = cli_posix_readlink_send(frame,
484                                 ev,
485                                 cli,
486                                 fname,
487                                 len);
488         if (req == NULL) {
489                 status = NT_STATUS_NO_MEMORY;
490                 goto fail;
491         }
492
493         if (!tevent_req_poll(req, ev)) {
494                 status = map_nt_error_from_unix(errno);
495                 goto fail;
496         }
497
498         status = cli_posix_readlink_recv(req, cli, linkpath, len);
499
500  fail:
501         TALLOC_FREE(frame);
502         return status;
503 }
504
505 /****************************************************************************
506  Hard link a file (UNIX extensions).
507 ****************************************************************************/
508
509 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
510                                         struct event_context *ev,
511                                         struct cli_state *cli,
512                                         const char *oldname,
513                                         const char *newname)
514 {
515         return cli_posix_link_internal_send(
516                 mem_ctx, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
517 }
518
519 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
520 {
521         return tevent_req_simple_recv_ntstatus(req);
522 }
523
524 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
525                         const char *oldname,
526                         const char *newname)
527 {
528         TALLOC_CTX *frame = talloc_stackframe();
529         struct event_context *ev = NULL;
530         struct tevent_req *req = NULL;
531         NTSTATUS status = NT_STATUS_OK;
532
533         if (cli_has_async_calls(cli)) {
534                 /*
535                  * Can't use sync call while an async call is in flight
536                  */
537                 status = NT_STATUS_INVALID_PARAMETER;
538                 goto fail;
539         }
540
541         ev = event_context_init(frame);
542         if (ev == NULL) {
543                 status = NT_STATUS_NO_MEMORY;
544                 goto fail;
545         }
546
547         req = cli_posix_hardlink_send(frame,
548                                 ev,
549                                 cli,
550                                 oldname,
551                                 newname);
552         if (req == NULL) {
553                 status = NT_STATUS_NO_MEMORY;
554                 goto fail;
555         }
556
557         if (!tevent_req_poll(req, ev)) {
558                 status = map_nt_error_from_unix(errno);
559                 goto fail;
560         }
561
562         status = cli_posix_hardlink_recv(req);
563
564  fail:
565         TALLOC_FREE(frame);
566         return status;
567 }
568
569 /****************************************************************************
570  Do a POSIX getfacl (UNIX extensions).
571 ****************************************************************************/
572
573 struct getfacl_state {
574         uint32_t num_data;
575         uint8_t *data;
576 };
577
578 static void cli_posix_getfacl_done(struct tevent_req *subreq);
579
580 struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
581                                         struct event_context *ev,
582                                         struct cli_state *cli,
583                                         const char *fname)
584 {
585         struct tevent_req *req = NULL, *subreq = NULL;
586         struct getfacl_state *state = NULL;
587
588         req = tevent_req_create(mem_ctx, &state, struct getfacl_state);
589         if (req == NULL) {
590                 return NULL;
591         }
592         subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
593                                     0, cli->max_xmit);
594         if (tevent_req_nomem(subreq, req)) {
595                 return tevent_req_post(req, ev);
596         }
597         tevent_req_set_callback(subreq, cli_posix_getfacl_done, req);
598         return req;
599 }
600
601 static void cli_posix_getfacl_done(struct tevent_req *subreq)
602 {
603         struct tevent_req *req = tevent_req_callback_data(
604                 subreq, struct tevent_req);
605         struct getfacl_state *state = tevent_req_data(
606                 req, struct getfacl_state);
607         NTSTATUS status;
608
609         status = cli_qpathinfo_recv(subreq, state, &state->data,
610                                     &state->num_data);
611         TALLOC_FREE(subreq);
612         if (tevent_req_nterror(req, status)) {
613                 return;
614         }
615         tevent_req_done(req);
616 }
617
618 NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
619                                 TALLOC_CTX *mem_ctx,
620                                 size_t *prb_size,
621                                 char **retbuf)
622 {
623         struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
624         NTSTATUS status;
625
626         if (tevent_req_is_nterror(req, &status)) {
627                 return status;
628         }
629         *prb_size = (size_t)state->num_data;
630         *retbuf = (char *)talloc_move(mem_ctx, &state->data);
631         return NT_STATUS_OK;
632 }
633
634 NTSTATUS cli_posix_getfacl(struct cli_state *cli,
635                         const char *fname,
636                         TALLOC_CTX *mem_ctx,
637                         size_t *prb_size,
638                         char **retbuf)
639 {
640         TALLOC_CTX *frame = talloc_stackframe();
641         struct event_context *ev = NULL;
642         struct tevent_req *req = NULL;
643         NTSTATUS status = NT_STATUS_OK;
644
645         if (cli_has_async_calls(cli)) {
646                 /*
647                  * Can't use sync call while an async call is in flight
648                  */
649                 status = NT_STATUS_INVALID_PARAMETER;
650                 goto fail;
651         }
652
653         ev = event_context_init(frame);
654         if (ev == NULL) {
655                 status = NT_STATUS_NO_MEMORY;
656                 goto fail;
657         }
658
659         req = cli_posix_getfacl_send(frame,
660                                 ev,
661                                 cli,
662                                 fname);
663         if (req == NULL) {
664                 status = NT_STATUS_NO_MEMORY;
665                 goto fail;
666         }
667
668         if (!tevent_req_poll(req, ev)) {
669                 status = map_nt_error_from_unix(errno);
670                 goto fail;
671         }
672
673         status = cli_posix_getfacl_recv(req, mem_ctx, prb_size, retbuf);
674
675  fail:
676         TALLOC_FREE(frame);
677         return status;
678 }
679
680 /****************************************************************************
681  Stat a file (UNIX extensions).
682 ****************************************************************************/
683
684 struct stat_state {
685         uint32_t num_data;
686         uint8_t *data;
687 };
688
689 static void cli_posix_stat_done(struct tevent_req *subreq);
690
691 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
692                                         struct event_context *ev,
693                                         struct cli_state *cli,
694                                         const char *fname)
695 {
696         struct tevent_req *req = NULL, *subreq = NULL;
697         struct stat_state *state = NULL;
698
699         req = tevent_req_create(mem_ctx, &state, struct stat_state);
700         if (req == NULL) {
701                 return NULL;
702         }
703         subreq = cli_qpathinfo_send(state, ev, cli, fname,
704                                     SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
705         if (tevent_req_nomem(subreq, req)) {
706                 return tevent_req_post(req, ev);
707         }
708         tevent_req_set_callback(subreq, cli_posix_stat_done, req);
709         return req;
710 }
711
712 static void cli_posix_stat_done(struct tevent_req *subreq)
713 {
714         struct tevent_req *req = tevent_req_callback_data(
715                                 subreq, struct tevent_req);
716         struct stat_state *state = tevent_req_data(req, struct stat_state);
717         NTSTATUS status;
718
719         status = cli_qpathinfo_recv(subreq, state, &state->data,
720                                     &state->num_data);
721         TALLOC_FREE(subreq);
722         if (tevent_req_nterror(req, status)) {
723                 return;
724         }
725         tevent_req_done(req);
726 }
727
728 NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
729                                 SMB_STRUCT_STAT *sbuf)
730 {
731         struct stat_state *state = tevent_req_data(req, struct stat_state);
732         NTSTATUS status;
733
734         if (tevent_req_is_nterror(req, &status)) {
735                 return status;
736         }
737
738         sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0);     /* total size, in bytes */
739         sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8);   /* number of blocks allocated */
740 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
741         sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
742 #else
743         /* assume 512 byte blocks */
744         sbuf->st_ex_blocks /= 512;
745 #endif
746         sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16));    /* time of last change */
747         sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24));    /* time of last access */
748         sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32));    /* time of last modification */
749
750         sbuf->st_ex_uid = (uid_t) IVAL(state->data,40);      /* user ID of owner */
751         sbuf->st_ex_gid = (gid_t) IVAL(state->data,48);      /* group ID of owner */
752         sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
753 #if defined(HAVE_MAKEDEV)
754         {
755                 uint32_t dev_major = IVAL(state->data,60);
756                 uint32_t dev_minor = IVAL(state->data,68);
757                 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
758         }
759 #endif
760         sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76);      /* inode */
761         sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84));     /* protection */
762         sbuf->st_ex_nlink = BIG_UINT(state->data,92); /* number of hard links */
763
764         return NT_STATUS_OK;
765 }
766
767 NTSTATUS cli_posix_stat(struct cli_state *cli,
768                         const char *fname,
769                         SMB_STRUCT_STAT *sbuf)
770 {
771         TALLOC_CTX *frame = talloc_stackframe();
772         struct event_context *ev = NULL;
773         struct tevent_req *req = NULL;
774         NTSTATUS status = NT_STATUS_OK;
775
776         if (cli_has_async_calls(cli)) {
777                 /*
778                  * Can't use sync call while an async call is in flight
779                  */
780                 status = NT_STATUS_INVALID_PARAMETER;
781                 goto fail;
782         }
783
784         ev = event_context_init(frame);
785         if (ev == NULL) {
786                 status = NT_STATUS_NO_MEMORY;
787                 goto fail;
788         }
789
790         req = cli_posix_stat_send(frame,
791                                 ev,
792                                 cli,
793                                 fname);
794         if (req == NULL) {
795                 status = NT_STATUS_NO_MEMORY;
796                 goto fail;
797         }
798
799         if (!tevent_req_poll(req, ev)) {
800                 status = map_nt_error_from_unix(errno);
801                 goto fail;
802         }
803
804         status = cli_posix_stat_recv(req, sbuf);
805
806  fail:
807         TALLOC_FREE(frame);
808         return status;
809 }
810
811 /****************************************************************************
812  Chmod or chown a file internal (UNIX extensions).
813 ****************************************************************************/
814
815 struct cli_posix_chown_chmod_internal_state {
816         uint8_t data[100];
817 };
818
819 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
820
821 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
822                                         struct event_context *ev,
823                                         struct cli_state *cli,
824                                         const char *fname,
825                                         uint32_t mode,
826                                         uint32_t uid,
827                                         uint32_t gid)
828 {
829         struct tevent_req *req = NULL, *subreq = NULL;
830         struct cli_posix_chown_chmod_internal_state *state = NULL;
831
832         req = tevent_req_create(mem_ctx, &state,
833                                 struct cli_posix_chown_chmod_internal_state);
834         if (req == NULL) {
835                 return NULL;
836         }
837
838         memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
839         memset(&state->data[40], '\0', 60);
840         SIVAL(state->data,40,uid);
841         SIVAL(state->data,48,gid);
842         SIVAL(state->data,84,mode);
843
844         subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
845                                       fname, state->data, sizeof(state->data));
846         if (tevent_req_nomem(subreq, req)) {
847                 return tevent_req_post(req, ev);
848         }
849         tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
850                                 req);
851         return req;
852 }
853
854 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
855 {
856         NTSTATUS status = cli_setpathinfo_recv(subreq);
857         tevent_req_simple_finish_ntstatus(subreq, status);
858 }
859
860 /****************************************************************************
861  chmod a file (UNIX extensions).
862 ****************************************************************************/
863
864 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
865                                         struct event_context *ev,
866                                         struct cli_state *cli,
867                                         const char *fname,
868                                         mode_t mode)
869 {
870         return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
871                         fname,
872                         unix_perms_to_wire(mode),
873                         SMB_UID_NO_CHANGE,
874                         SMB_GID_NO_CHANGE);
875 }
876
877 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
878 {
879         return tevent_req_simple_recv_ntstatus(req);
880 }
881
882 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
883 {
884         TALLOC_CTX *frame = talloc_stackframe();
885         struct event_context *ev = NULL;
886         struct tevent_req *req = NULL;
887         NTSTATUS status = NT_STATUS_OK;
888
889         if (cli_has_async_calls(cli)) {
890                 /*
891                  * Can't use sync call while an async call is in flight
892                  */
893                 status = NT_STATUS_INVALID_PARAMETER;
894                 goto fail;
895         }
896
897         ev = event_context_init(frame);
898         if (ev == NULL) {
899                 status = NT_STATUS_NO_MEMORY;
900                 goto fail;
901         }
902
903         req = cli_posix_chmod_send(frame,
904                                 ev,
905                                 cli,
906                                 fname,
907                                 mode);
908         if (req == NULL) {
909                 status = NT_STATUS_NO_MEMORY;
910                 goto fail;
911         }
912
913         if (!tevent_req_poll(req, ev)) {
914                 status = map_nt_error_from_unix(errno);
915                 goto fail;
916         }
917
918         status = cli_posix_chmod_recv(req);
919
920  fail:
921         TALLOC_FREE(frame);
922         return status;
923 }
924
925 /****************************************************************************
926  chown a file (UNIX extensions).
927 ****************************************************************************/
928
929 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
930                                         struct event_context *ev,
931                                         struct cli_state *cli,
932                                         const char *fname,
933                                         uid_t uid,
934                                         gid_t gid)
935 {
936         return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
937                         fname,
938                         SMB_MODE_NO_CHANGE,
939                         (uint32_t)uid,
940                         (uint32_t)gid);
941 }
942
943 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
944 {
945         return tevent_req_simple_recv_ntstatus(req);
946 }
947
948 NTSTATUS cli_posix_chown(struct cli_state *cli,
949                         const char *fname,
950                         uid_t uid,
951                         gid_t gid)
952 {
953         TALLOC_CTX *frame = talloc_stackframe();
954         struct event_context *ev = NULL;
955         struct tevent_req *req = NULL;
956         NTSTATUS status = NT_STATUS_OK;
957
958         if (cli_has_async_calls(cli)) {
959                 /*
960                  * Can't use sync call while an async call is in flight
961                  */
962                 status = NT_STATUS_INVALID_PARAMETER;
963                 goto fail;
964         }
965
966         ev = event_context_init(frame);
967         if (ev == NULL) {
968                 status = NT_STATUS_NO_MEMORY;
969                 goto fail;
970         }
971
972         req = cli_posix_chown_send(frame,
973                                 ev,
974                                 cli,
975                                 fname,
976                                 uid,
977                                 gid);
978         if (req == NULL) {
979                 status = NT_STATUS_NO_MEMORY;
980                 goto fail;
981         }
982
983         if (!tevent_req_poll(req, ev)) {
984                 status = map_nt_error_from_unix(errno);
985                 goto fail;
986         }
987
988         status = cli_posix_chown_recv(req);
989
990  fail:
991         TALLOC_FREE(frame);
992         return status;
993 }
994
995 /****************************************************************************
996  Rename a file.
997 ****************************************************************************/
998
999 static void cli_rename_done(struct tevent_req *subreq);
1000
1001 struct cli_rename_state {
1002         uint16_t vwv[1];
1003 };
1004
1005 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1006                                 struct event_context *ev,
1007                                 struct cli_state *cli,
1008                                 const char *fname_src,
1009                                 const char *fname_dst)
1010 {
1011         struct tevent_req *req = NULL, *subreq = NULL;
1012         struct cli_rename_state *state = NULL;
1013         uint8_t additional_flags = 0;
1014         uint8_t *bytes = NULL;
1015
1016         req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1017         if (req == NULL) {
1018                 return NULL;
1019         }
1020
1021         SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1022
1023         bytes = talloc_array(state, uint8_t, 1);
1024         if (tevent_req_nomem(bytes, req)) {
1025                 return tevent_req_post(req, ev);
1026         }
1027         bytes[0] = 4;
1028         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1029                                    strlen(fname_src)+1, NULL);
1030         if (tevent_req_nomem(bytes, req)) {
1031                 return tevent_req_post(req, ev);
1032         }
1033
1034         bytes = talloc_realloc(state, bytes, uint8_t,
1035                         talloc_get_size(bytes)+1);
1036         if (tevent_req_nomem(bytes, req)) {
1037                 return tevent_req_post(req, ev);
1038         }
1039
1040         bytes[talloc_get_size(bytes)-1] = 4;
1041         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1042                                    strlen(fname_dst)+1, NULL);
1043         if (tevent_req_nomem(bytes, req)) {
1044                 return tevent_req_post(req, ev);
1045         }
1046
1047         subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1048                               1, state->vwv, talloc_get_size(bytes), bytes);
1049         if (tevent_req_nomem(subreq, req)) {
1050                 return tevent_req_post(req, ev);
1051         }
1052         tevent_req_set_callback(subreq, cli_rename_done, req);
1053         return req;
1054 }
1055
1056 static void cli_rename_done(struct tevent_req *subreq)
1057 {
1058         struct tevent_req *req = tevent_req_callback_data(
1059                                 subreq, struct tevent_req);
1060         NTSTATUS status;
1061
1062         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1063         TALLOC_FREE(subreq);
1064         if (tevent_req_nterror(req, status)) {
1065                 return;
1066         }
1067         tevent_req_done(req);
1068 }
1069
1070 NTSTATUS cli_rename_recv(struct tevent_req *req)
1071 {
1072         return tevent_req_simple_recv_ntstatus(req);
1073 }
1074
1075 NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1076 {
1077         TALLOC_CTX *frame = talloc_stackframe();
1078         struct event_context *ev;
1079         struct tevent_req *req;
1080         NTSTATUS status = NT_STATUS_OK;
1081
1082         if (cli_has_async_calls(cli)) {
1083                 /*
1084                  * Can't use sync call while an async call is in flight
1085                  */
1086                 status = NT_STATUS_INVALID_PARAMETER;
1087                 goto fail;
1088         }
1089
1090         ev = event_context_init(frame);
1091         if (ev == NULL) {
1092                 status = NT_STATUS_NO_MEMORY;
1093                 goto fail;
1094         }
1095
1096         req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
1097         if (req == NULL) {
1098                 status = NT_STATUS_NO_MEMORY;
1099                 goto fail;
1100         }
1101
1102         if (!tevent_req_poll(req, ev)) {
1103                 status = map_nt_error_from_unix(errno);
1104                 goto fail;
1105         }
1106
1107         status = cli_rename_recv(req);
1108
1109  fail:
1110         TALLOC_FREE(frame);
1111         return status;
1112 }
1113
1114 /****************************************************************************
1115  NT Rename a file.
1116 ****************************************************************************/
1117
1118 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1119
1120 struct cli_ntrename_internal_state {
1121         uint16_t vwv[4];
1122 };
1123
1124 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1125                                 struct event_context *ev,
1126                                 struct cli_state *cli,
1127                                 const char *fname_src,
1128                                 const char *fname_dst,
1129                                 uint16_t rename_flag)
1130 {
1131         struct tevent_req *req = NULL, *subreq = NULL;
1132         struct cli_ntrename_internal_state *state = NULL;
1133         uint8_t additional_flags = 0;
1134         uint8_t *bytes = NULL;
1135
1136         req = tevent_req_create(mem_ctx, &state,
1137                                 struct cli_ntrename_internal_state);
1138         if (req == NULL) {
1139                 return NULL;
1140         }
1141
1142         SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1143         SSVAL(state->vwv+1, 0, rename_flag);
1144
1145         bytes = talloc_array(state, uint8_t, 1);
1146         if (tevent_req_nomem(bytes, req)) {
1147                 return tevent_req_post(req, ev);
1148         }
1149         bytes[0] = 4;
1150         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1151                                    strlen(fname_src)+1, NULL);
1152         if (tevent_req_nomem(bytes, req)) {
1153                 return tevent_req_post(req, ev);
1154         }
1155
1156         bytes = talloc_realloc(state, bytes, uint8_t,
1157                         talloc_get_size(bytes)+1);
1158         if (tevent_req_nomem(bytes, req)) {
1159                 return tevent_req_post(req, ev);
1160         }
1161
1162         bytes[talloc_get_size(bytes)-1] = 4;
1163         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1164                                    strlen(fname_dst)+1, NULL);
1165         if (tevent_req_nomem(bytes, req)) {
1166                 return tevent_req_post(req, ev);
1167         }
1168
1169         subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1170                               4, state->vwv, talloc_get_size(bytes), bytes);
1171         if (tevent_req_nomem(subreq, req)) {
1172                 return tevent_req_post(req, ev);
1173         }
1174         tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1175         return req;
1176 }
1177
1178 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1179 {
1180         struct tevent_req *req = tevent_req_callback_data(
1181                                 subreq, struct tevent_req);
1182         NTSTATUS status;
1183
1184         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1185         TALLOC_FREE(subreq);
1186         if (tevent_req_nterror(req, status)) {
1187                 return;
1188         }
1189         tevent_req_done(req);
1190 }
1191
1192 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1193 {
1194         return tevent_req_simple_recv_ntstatus(req);
1195 }
1196
1197 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1198                                 struct event_context *ev,
1199                                 struct cli_state *cli,
1200                                 const char *fname_src,
1201                                 const char *fname_dst)
1202 {
1203         return cli_ntrename_internal_send(mem_ctx,
1204                                           ev,
1205                                           cli,
1206                                           fname_src,
1207                                           fname_dst,
1208                                           RENAME_FLAG_RENAME);
1209 }
1210
1211 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1212 {
1213         return cli_ntrename_internal_recv(req);
1214 }
1215
1216 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1217 {
1218         TALLOC_CTX *frame = talloc_stackframe();
1219         struct event_context *ev;
1220         struct tevent_req *req;
1221         NTSTATUS status = NT_STATUS_OK;
1222
1223         if (cli_has_async_calls(cli)) {
1224                 /*
1225                  * Can't use sync call while an async call is in flight
1226                  */
1227                 status = NT_STATUS_INVALID_PARAMETER;
1228                 goto fail;
1229         }
1230
1231         ev = event_context_init(frame);
1232         if (ev == NULL) {
1233                 status = NT_STATUS_NO_MEMORY;
1234                 goto fail;
1235         }
1236
1237         req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1238         if (req == NULL) {
1239                 status = NT_STATUS_NO_MEMORY;
1240                 goto fail;
1241         }
1242
1243         if (!tevent_req_poll(req, ev)) {
1244                 status = map_nt_error_from_unix(errno);
1245                 goto fail;
1246         }
1247
1248         status = cli_ntrename_recv(req);
1249
1250  fail:
1251         TALLOC_FREE(frame);
1252         return status;
1253 }
1254
1255 /****************************************************************************
1256  NT hardlink a file.
1257 ****************************************************************************/
1258
1259 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1260                                 struct event_context *ev,
1261                                 struct cli_state *cli,
1262                                 const char *fname_src,
1263                                 const char *fname_dst)
1264 {
1265         return cli_ntrename_internal_send(mem_ctx,
1266                                           ev,
1267                                           cli,
1268                                           fname_src,
1269                                           fname_dst,
1270                                           RENAME_FLAG_HARD_LINK);
1271 }
1272
1273 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1274 {
1275         return cli_ntrename_internal_recv(req);
1276 }
1277
1278 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1279 {
1280         TALLOC_CTX *frame = talloc_stackframe();
1281         struct event_context *ev;
1282         struct tevent_req *req;
1283         NTSTATUS status = NT_STATUS_OK;
1284
1285         if (cli_has_async_calls(cli)) {
1286                 /*
1287                  * Can't use sync call while an async call is in flight
1288                  */
1289                 status = NT_STATUS_INVALID_PARAMETER;
1290                 goto fail;
1291         }
1292
1293         ev = event_context_init(frame);
1294         if (ev == NULL) {
1295                 status = NT_STATUS_NO_MEMORY;
1296                 goto fail;
1297         }
1298
1299         req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1300         if (req == NULL) {
1301                 status = NT_STATUS_NO_MEMORY;
1302                 goto fail;
1303         }
1304
1305         if (!tevent_req_poll(req, ev)) {
1306                 status = map_nt_error_from_unix(errno);
1307                 goto fail;
1308         }
1309
1310         status = cli_nt_hardlink_recv(req);
1311
1312  fail:
1313         TALLOC_FREE(frame);
1314         return status;
1315 }
1316
1317 /****************************************************************************
1318  Delete a file.
1319 ****************************************************************************/
1320
1321 static void cli_unlink_done(struct tevent_req *subreq);
1322
1323 struct cli_unlink_state {
1324         uint16_t vwv[1];
1325 };
1326
1327 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1328                                 struct event_context *ev,
1329                                 struct cli_state *cli,
1330                                 const char *fname,
1331                                 uint16_t mayhave_attrs)
1332 {
1333         struct tevent_req *req = NULL, *subreq = NULL;
1334         struct cli_unlink_state *state = NULL;
1335         uint8_t additional_flags = 0;
1336         uint8_t *bytes = NULL;
1337
1338         req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1339         if (req == NULL) {
1340                 return NULL;
1341         }
1342
1343         SSVAL(state->vwv+0, 0, mayhave_attrs);
1344
1345         bytes = talloc_array(state, uint8_t, 1);
1346         if (tevent_req_nomem(bytes, req)) {
1347                 return tevent_req_post(req, ev);
1348         }
1349         bytes[0] = 4;
1350         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
1351                                    strlen(fname)+1, NULL);
1352
1353         if (tevent_req_nomem(bytes, req)) {
1354                 return tevent_req_post(req, ev);
1355         }
1356
1357         subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1358                                 1, state->vwv, talloc_get_size(bytes), bytes);
1359         if (tevent_req_nomem(subreq, req)) {
1360                 return tevent_req_post(req, ev);
1361         }
1362         tevent_req_set_callback(subreq, cli_unlink_done, req);
1363         return req;
1364 }
1365
1366 static void cli_unlink_done(struct tevent_req *subreq)
1367 {
1368         struct tevent_req *req = tevent_req_callback_data(
1369                 subreq, struct tevent_req);
1370         NTSTATUS status;
1371
1372         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1373         TALLOC_FREE(subreq);
1374         if (tevent_req_nterror(req, status)) {
1375                 return;
1376         }
1377         tevent_req_done(req);
1378 }
1379
1380 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1381 {
1382         return tevent_req_simple_recv_ntstatus(req);
1383 }
1384
1385 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1386 {
1387         TALLOC_CTX *frame = talloc_stackframe();
1388         struct event_context *ev;
1389         struct tevent_req *req;
1390         NTSTATUS status = NT_STATUS_OK;
1391
1392         if (cli_has_async_calls(cli)) {
1393                 /*
1394                  * Can't use sync call while an async call is in flight
1395                  */
1396                 status = NT_STATUS_INVALID_PARAMETER;
1397                 goto fail;
1398         }
1399
1400         ev = event_context_init(frame);
1401         if (ev == NULL) {
1402                 status = NT_STATUS_NO_MEMORY;
1403                 goto fail;
1404         }
1405
1406         req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1407         if (req == NULL) {
1408                 status = NT_STATUS_NO_MEMORY;
1409                 goto fail;
1410         }
1411
1412         if (!tevent_req_poll(req, ev)) {
1413                 status = map_nt_error_from_unix(errno);
1414                 goto fail;
1415         }
1416
1417         status = cli_unlink_recv(req);
1418
1419  fail:
1420         TALLOC_FREE(frame);
1421         return status;
1422 }
1423
1424 /****************************************************************************
1425  Create a directory.
1426 ****************************************************************************/
1427
1428 static void cli_mkdir_done(struct tevent_req *subreq);
1429
1430 struct cli_mkdir_state {
1431         int dummy;
1432 };
1433
1434 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1435                                   struct event_context *ev,
1436                                   struct cli_state *cli,
1437                                   const char *dname)
1438 {
1439         struct tevent_req *req = NULL, *subreq = NULL;
1440         struct cli_mkdir_state *state = NULL;
1441         uint8_t additional_flags = 0;
1442         uint8_t *bytes = NULL;
1443
1444         req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1445         if (req == NULL) {
1446                 return NULL;
1447         }
1448
1449         bytes = talloc_array(state, uint8_t, 1);
1450         if (tevent_req_nomem(bytes, req)) {
1451                 return tevent_req_post(req, ev);
1452         }
1453         bytes[0] = 4;
1454         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1455                                    strlen(dname)+1, NULL);
1456
1457         if (tevent_req_nomem(bytes, req)) {
1458                 return tevent_req_post(req, ev);
1459         }
1460
1461         subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1462                               0, NULL, talloc_get_size(bytes), bytes);
1463         if (tevent_req_nomem(subreq, req)) {
1464                 return tevent_req_post(req, ev);
1465         }
1466         tevent_req_set_callback(subreq, cli_mkdir_done, req);
1467         return req;
1468 }
1469
1470 static void cli_mkdir_done(struct tevent_req *subreq)
1471 {
1472         struct tevent_req *req = tevent_req_callback_data(
1473                 subreq, struct tevent_req);
1474         NTSTATUS status;
1475
1476         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1477         TALLOC_FREE(subreq);
1478         if (tevent_req_nterror(req, status)) {
1479                 return;
1480         }
1481         tevent_req_done(req);
1482 }
1483
1484 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1485 {
1486         return tevent_req_simple_recv_ntstatus(req);
1487 }
1488
1489 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1490 {
1491         TALLOC_CTX *frame = talloc_stackframe();
1492         struct event_context *ev;
1493         struct tevent_req *req;
1494         NTSTATUS status = NT_STATUS_OK;
1495
1496         if (cli_has_async_calls(cli)) {
1497                 /*
1498                  * Can't use sync call while an async call is in flight
1499                  */
1500                 status = NT_STATUS_INVALID_PARAMETER;
1501                 goto fail;
1502         }
1503
1504         ev = event_context_init(frame);
1505         if (ev == NULL) {
1506                 status = NT_STATUS_NO_MEMORY;
1507                 goto fail;
1508         }
1509
1510         req = cli_mkdir_send(frame, ev, cli, dname);
1511         if (req == NULL) {
1512                 status = NT_STATUS_NO_MEMORY;
1513                 goto fail;
1514         }
1515
1516         if (!tevent_req_poll(req, ev)) {
1517                 status = map_nt_error_from_unix(errno);
1518                 goto fail;
1519         }
1520
1521         status = cli_mkdir_recv(req);
1522
1523  fail:
1524         TALLOC_FREE(frame);
1525         return status;
1526 }
1527
1528 /****************************************************************************
1529  Remove a directory.
1530 ****************************************************************************/
1531
1532 static void cli_rmdir_done(struct tevent_req *subreq);
1533
1534 struct cli_rmdir_state {
1535         int dummy;
1536 };
1537
1538 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1539                                   struct event_context *ev,
1540                                   struct cli_state *cli,
1541                                   const char *dname)
1542 {
1543         struct tevent_req *req = NULL, *subreq = NULL;
1544         struct cli_rmdir_state *state = NULL;
1545         uint8_t additional_flags = 0;
1546         uint8_t *bytes = NULL;
1547
1548         req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1549         if (req == NULL) {
1550                 return NULL;
1551         }
1552
1553         bytes = talloc_array(state, uint8_t, 1);
1554         if (tevent_req_nomem(bytes, req)) {
1555                 return tevent_req_post(req, ev);
1556         }
1557         bytes[0] = 4;
1558         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1559                                    strlen(dname)+1, NULL);
1560
1561         if (tevent_req_nomem(bytes, req)) {
1562                 return tevent_req_post(req, ev);
1563         }
1564
1565         subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1566                               0, NULL, talloc_get_size(bytes), bytes);
1567         if (tevent_req_nomem(subreq, req)) {
1568                 return tevent_req_post(req, ev);
1569         }
1570         tevent_req_set_callback(subreq, cli_rmdir_done, req);
1571         return req;
1572 }
1573
1574 static void cli_rmdir_done(struct tevent_req *subreq)
1575 {
1576         struct tevent_req *req = tevent_req_callback_data(
1577                 subreq, struct tevent_req);
1578         NTSTATUS status;
1579
1580         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1581         TALLOC_FREE(subreq);
1582         if (tevent_req_nterror(req, status)) {
1583                 return;
1584         }
1585         tevent_req_done(req);
1586 }
1587
1588 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1589 {
1590         return tevent_req_simple_recv_ntstatus(req);
1591 }
1592
1593 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1594 {
1595         TALLOC_CTX *frame = talloc_stackframe();
1596         struct event_context *ev;
1597         struct tevent_req *req;
1598         NTSTATUS status = NT_STATUS_OK;
1599
1600         if (cli_has_async_calls(cli)) {
1601                 /*
1602                  * Can't use sync call while an async call is in flight
1603                  */
1604                 status = NT_STATUS_INVALID_PARAMETER;
1605                 goto fail;
1606         }
1607
1608         ev = event_context_init(frame);
1609         if (ev == NULL) {
1610                 status = NT_STATUS_NO_MEMORY;
1611                 goto fail;
1612         }
1613
1614         req = cli_rmdir_send(frame, ev, cli, dname);
1615         if (req == NULL) {
1616                 status = NT_STATUS_NO_MEMORY;
1617                 goto fail;
1618         }
1619
1620         if (!tevent_req_poll(req, ev)) {
1621                 status = map_nt_error_from_unix(errno);
1622                 goto fail;
1623         }
1624
1625         status = cli_rmdir_recv(req);
1626
1627  fail:
1628         TALLOC_FREE(frame);
1629         return status;
1630 }
1631
1632 /****************************************************************************
1633  Set or clear the delete on close flag.
1634 ****************************************************************************/
1635
1636 struct doc_state {
1637         uint16_t setup;
1638         uint8_t param[6];
1639         uint8_t data[1];
1640 };
1641
1642 static void cli_nt_delete_on_close_done(struct tevent_req *subreq)
1643 {
1644         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
1645                                          NULL, 0, NULL, NULL, 0, NULL);
1646         tevent_req_simple_finish_ntstatus(subreq, status);
1647 }
1648
1649 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1650                                         struct event_context *ev,
1651                                         struct cli_state *cli,
1652                                         uint16_t fnum,
1653                                         bool flag)
1654 {
1655         struct tevent_req *req = NULL, *subreq = NULL;
1656         struct doc_state *state = NULL;
1657
1658         req = tevent_req_create(mem_ctx, &state, struct doc_state);
1659         if (req == NULL) {
1660                 return NULL;
1661         }
1662
1663         /* Setup setup word. */
1664         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1665
1666         /* Setup param array. */
1667         SSVAL(state->param,0,fnum);
1668         SSVAL(state->param,2,SMB_SET_FILE_DISPOSITION_INFO);
1669
1670         /* Setup data array. */
1671         SCVAL(&state->data[0], 0, flag ? 1 : 0);
1672
1673         subreq = cli_trans_send(state,                  /* mem ctx. */
1674                                 ev,                     /* event ctx. */
1675                                 cli,                    /* cli_state. */
1676                                 SMBtrans2,              /* cmd. */
1677                                 NULL,                   /* pipe name. */
1678                                 -1,                     /* fid. */
1679                                 0,                      /* function. */
1680                                 0,                      /* flags. */
1681                                 &state->setup,          /* setup. */
1682                                 1,                      /* num setup uint16_t words. */
1683                                 0,                      /* max returned setup. */
1684                                 state->param,           /* param. */
1685                                 6,                      /* num param. */
1686                                 2,                      /* max returned param. */
1687                                 state->data,            /* data. */
1688                                 1,                      /* num data. */
1689                                 0);                     /* max returned data. */
1690
1691         if (tevent_req_nomem(subreq, req)) {
1692                 return tevent_req_post(req, ev);
1693         }
1694         tevent_req_set_callback(subreq, cli_nt_delete_on_close_done, req);
1695         return req;
1696 }
1697
1698 NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
1699 {
1700         return tevent_req_simple_recv_ntstatus(req);
1701 }
1702
1703 NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1704 {
1705         TALLOC_CTX *frame = talloc_stackframe();
1706         struct event_context *ev = NULL;
1707         struct tevent_req *req = NULL;
1708         NTSTATUS status = NT_STATUS_OK;
1709
1710         if (cli_has_async_calls(cli)) {
1711                 /*
1712                  * Can't use sync call while an async call is in flight
1713                  */
1714                 status = NT_STATUS_INVALID_PARAMETER;
1715                 goto fail;
1716         }
1717
1718         ev = event_context_init(frame);
1719         if (ev == NULL) {
1720                 status = NT_STATUS_NO_MEMORY;
1721                 goto fail;
1722         }
1723
1724         req = cli_nt_delete_on_close_send(frame,
1725                                 ev,
1726                                 cli,
1727                                 fnum,
1728                                 flag);
1729         if (req == NULL) {
1730                 status = NT_STATUS_NO_MEMORY;
1731                 goto fail;
1732         }
1733
1734         if (!tevent_req_poll(req, ev)) {
1735                 status = map_nt_error_from_unix(errno);
1736                 goto fail;
1737         }
1738
1739         status = cli_nt_delete_on_close_recv(req);
1740
1741  fail:
1742         TALLOC_FREE(frame);
1743         return status;
1744 }
1745
1746 struct cli_ntcreate_state {
1747         uint16_t vwv[24];
1748         uint16_t fnum;
1749 };
1750
1751 static void cli_ntcreate_done(struct tevent_req *subreq);
1752
1753 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
1754                                      struct event_context *ev,
1755                                      struct cli_state *cli,
1756                                      const char *fname,
1757                                      uint32_t CreatFlags,
1758                                      uint32_t DesiredAccess,
1759                                      uint32_t FileAttributes,
1760                                      uint32_t ShareAccess,
1761                                      uint32_t CreateDisposition,
1762                                      uint32_t CreateOptions,
1763                                      uint8_t SecurityFlags)
1764 {
1765         struct tevent_req *req, *subreq;
1766         struct cli_ntcreate_state *state;
1767         uint16_t *vwv;
1768         uint8_t *bytes;
1769         size_t converted_len;
1770
1771         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
1772         if (req == NULL) {
1773                 return NULL;
1774         }
1775
1776         vwv = state->vwv;
1777
1778         SCVAL(vwv+0, 0, 0xFF);
1779         SCVAL(vwv+0, 1, 0);
1780         SSVAL(vwv+1, 0, 0);
1781         SCVAL(vwv+2, 0, 0);
1782
1783         if (cli->use_oplocks) {
1784                 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1785         }
1786         SIVAL(vwv+3, 1, CreatFlags);
1787         SIVAL(vwv+5, 1, 0x0);   /* RootDirectoryFid */
1788         SIVAL(vwv+7, 1, DesiredAccess);
1789         SIVAL(vwv+9, 1, 0x0);   /* AllocationSize */
1790         SIVAL(vwv+11, 1, 0x0);  /* AllocationSize */
1791         SIVAL(vwv+13, 1, FileAttributes);
1792         SIVAL(vwv+15, 1, ShareAccess);
1793         SIVAL(vwv+17, 1, CreateDisposition);
1794         SIVAL(vwv+19, 1, CreateOptions);
1795         SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1796         SCVAL(vwv+23, 1, SecurityFlags);
1797
1798         bytes = talloc_array(state, uint8_t, 0);
1799         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
1800                                    fname, strlen(fname)+1,
1801                                    &converted_len);
1802
1803         /* sigh. this copes with broken netapp filer behaviour */
1804         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL);
1805
1806         if (tevent_req_nomem(bytes, req)) {
1807                 return tevent_req_post(req, ev);
1808         }
1809
1810         SSVAL(vwv+2, 1, converted_len);
1811
1812         subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
1813                               talloc_get_size(bytes), bytes);
1814         if (tevent_req_nomem(subreq, req)) {
1815                 return tevent_req_post(req, ev);
1816         }
1817         tevent_req_set_callback(subreq, cli_ntcreate_done, req);
1818         return req;
1819 }
1820
1821 static void cli_ntcreate_done(struct tevent_req *subreq)
1822 {
1823         struct tevent_req *req = tevent_req_callback_data(
1824                 subreq, struct tevent_req);
1825         struct cli_ntcreate_state *state = tevent_req_data(
1826                 req, struct cli_ntcreate_state);
1827         uint8_t wct;
1828         uint16_t *vwv;
1829         uint32_t num_bytes;
1830         uint8_t *bytes;
1831         uint8_t *inbuf;
1832         NTSTATUS status;
1833
1834         status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv,
1835                               &num_bytes, &bytes);
1836         TALLOC_FREE(subreq);
1837         if (tevent_req_nterror(req, status)) {
1838                 return;
1839         }
1840         state->fnum = SVAL(vwv+2, 1);
1841         tevent_req_done(req);
1842 }
1843
1844 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
1845 {
1846         struct cli_ntcreate_state *state = tevent_req_data(
1847                 req, struct cli_ntcreate_state);
1848         NTSTATUS status;
1849
1850         if (tevent_req_is_nterror(req, &status)) {
1851                 return status;
1852         }
1853         *pfnum = state->fnum;
1854         return NT_STATUS_OK;
1855 }
1856
1857 NTSTATUS cli_ntcreate(struct cli_state *cli,
1858                       const char *fname,
1859                       uint32_t CreatFlags,
1860                       uint32_t DesiredAccess,
1861                       uint32_t FileAttributes,
1862                       uint32_t ShareAccess,
1863                       uint32_t CreateDisposition,
1864                       uint32_t CreateOptions,
1865                       uint8_t SecurityFlags,
1866                       uint16_t *pfid)
1867 {
1868         TALLOC_CTX *frame = talloc_stackframe();
1869         struct event_context *ev;
1870         struct tevent_req *req;
1871         NTSTATUS status = NT_STATUS_OK;
1872
1873         if (cli_has_async_calls(cli)) {
1874                 /*
1875                  * Can't use sync call while an async call is in flight
1876                  */
1877                 status = NT_STATUS_INVALID_PARAMETER;
1878                 goto fail;
1879         }
1880
1881         ev = event_context_init(frame);
1882         if (ev == NULL) {
1883                 status = NT_STATUS_NO_MEMORY;
1884                 goto fail;
1885         }
1886
1887         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
1888                                 DesiredAccess, FileAttributes, ShareAccess,
1889                                 CreateDisposition, CreateOptions,
1890                                 SecurityFlags);
1891         if (req == NULL) {
1892                 status = NT_STATUS_NO_MEMORY;
1893                 goto fail;
1894         }
1895
1896         if (!tevent_req_poll(req, ev)) {
1897                 status = map_nt_error_from_unix(errno);
1898                 goto fail;
1899         }
1900
1901         status = cli_ntcreate_recv(req, pfid);
1902  fail:
1903         TALLOC_FREE(frame);
1904         return status;
1905 }
1906
1907 /****************************************************************************
1908  Open a file
1909  WARNING: if you open with O_WRONLY then getattrE won't work!
1910 ****************************************************************************/
1911
1912 struct cli_open_state {
1913         uint16_t vwv[15];
1914         uint16_t fnum;
1915         struct iovec bytes;
1916 };
1917
1918 static void cli_open_done(struct tevent_req *subreq);
1919
1920 struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx,
1921                                    struct event_context *ev,
1922                                    struct cli_state *cli, const char *fname,
1923                                    int flags, int share_mode,
1924                                    struct tevent_req **psmbreq)
1925 {
1926         struct tevent_req *req, *subreq;
1927         struct cli_open_state *state;
1928         unsigned openfn;
1929         unsigned accessmode;
1930         uint8_t additional_flags;
1931         uint8_t *bytes;
1932
1933         req = tevent_req_create(mem_ctx, &state, struct cli_open_state);
1934         if (req == NULL) {
1935                 return NULL;
1936         }
1937
1938         openfn = 0;
1939         if (flags & O_CREAT) {
1940                 openfn |= (1<<4);
1941         }
1942         if (!(flags & O_EXCL)) {
1943                 if (flags & O_TRUNC)
1944                         openfn |= (1<<1);
1945                 else
1946                         openfn |= (1<<0);
1947         }
1948
1949         accessmode = (share_mode<<4);
1950
1951         if ((flags & O_ACCMODE) == O_RDWR) {
1952                 accessmode |= 2;
1953         } else if ((flags & O_ACCMODE) == O_WRONLY) {
1954                 accessmode |= 1;
1955         }
1956
1957 #if defined(O_SYNC)
1958         if ((flags & O_SYNC) == O_SYNC) {
1959                 accessmode |= (1<<14);
1960         }
1961 #endif /* O_SYNC */
1962
1963         if (share_mode == DENY_FCB) {
1964                 accessmode = 0xFF;
1965         }
1966
1967         SCVAL(state->vwv + 0, 0, 0xFF);
1968         SCVAL(state->vwv + 0, 1, 0);
1969         SSVAL(state->vwv + 1, 0, 0);
1970         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
1971         SSVAL(state->vwv + 3, 0, accessmode);
1972         SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
1973         SSVAL(state->vwv + 5, 0, 0);
1974         SIVAL(state->vwv + 6, 0, 0);
1975         SSVAL(state->vwv + 8, 0, openfn);
1976         SIVAL(state->vwv + 9, 0, 0);
1977         SIVAL(state->vwv + 11, 0, 0);
1978         SIVAL(state->vwv + 13, 0, 0);
1979
1980         additional_flags = 0;
1981
1982         if (cli->use_oplocks) {
1983                 /* if using oplocks then ask for a batch oplock via
1984                    core and extended methods */
1985                 additional_flags =
1986                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
1987                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
1988         }
1989
1990         bytes = talloc_array(state, uint8_t, 0);
1991         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
1992                                    strlen(fname)+1, NULL);
1993
1994         if (tevent_req_nomem(bytes, req)) {
1995                 return tevent_req_post(req, ev);
1996         }
1997
1998         state->bytes.iov_base = (void *)bytes;
1999         state->bytes.iov_len = talloc_get_size(bytes);
2000
2001         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2002                                     15, state->vwv, 1, &state->bytes);
2003         if (subreq == NULL) {
2004                 TALLOC_FREE(req);
2005                 return NULL;
2006         }
2007         tevent_req_set_callback(subreq, cli_open_done, req);
2008         *psmbreq = subreq;
2009         return req;
2010 }
2011
2012 struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
2013                                  struct cli_state *cli, const char *fname,
2014                                  int flags, int share_mode)
2015 {
2016         struct tevent_req *req, *subreq;
2017         NTSTATUS status;
2018
2019         req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode,
2020                               &subreq);
2021         if (req == NULL) {
2022                 return NULL;
2023         }
2024
2025         status = cli_smb_req_send(subreq);
2026         if (tevent_req_nterror(req, status)) {
2027                 return tevent_req_post(req, ev);
2028         }
2029         return req;
2030 }
2031
2032 static void cli_open_done(struct tevent_req *subreq)
2033 {
2034         struct tevent_req *req = tevent_req_callback_data(
2035                 subreq, struct tevent_req);
2036         struct cli_open_state *state = tevent_req_data(
2037                 req, struct cli_open_state);
2038         uint8_t wct;
2039         uint16_t *vwv;
2040         uint8_t *inbuf;
2041         NTSTATUS status;
2042
2043         status = cli_smb_recv(subreq, state, &inbuf, 3, &wct, &vwv, NULL,
2044                               NULL);
2045         TALLOC_FREE(subreq);
2046         if (tevent_req_nterror(req, status)) {
2047                 return;
2048         }
2049         state->fnum = SVAL(vwv+2, 0);
2050         tevent_req_done(req);
2051 }
2052
2053 NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum)
2054 {
2055         struct cli_open_state *state = tevent_req_data(
2056                 req, struct cli_open_state);
2057         NTSTATUS status;
2058
2059         if (tevent_req_is_nterror(req, &status)) {
2060                 return status;
2061         }
2062         *pfnum = state->fnum;
2063         return NT_STATUS_OK;
2064 }
2065
2066 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2067              int share_mode, uint16_t *pfnum)
2068 {
2069         TALLOC_CTX *frame = talloc_stackframe();
2070         struct event_context *ev;
2071         struct tevent_req *req;
2072         NTSTATUS status = NT_STATUS_OK;
2073
2074         if (cli_has_async_calls(cli)) {
2075                 /*
2076                  * Can't use sync call while an async call is in flight
2077                  */
2078                 status = NT_STATUS_INVALID_PARAMETER;
2079                 goto fail;
2080         }
2081
2082         ev = event_context_init(frame);
2083         if (ev == NULL) {
2084                 status = NT_STATUS_NO_MEMORY;
2085                 goto fail;
2086         }
2087
2088         req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
2089         if (req == NULL) {
2090                 status = NT_STATUS_NO_MEMORY;
2091                 goto fail;
2092         }
2093
2094         if (!tevent_req_poll(req, ev)) {
2095                 status = map_nt_error_from_unix(errno);
2096                 goto fail;
2097         }
2098
2099         status = cli_open_recv(req, pfnum);
2100  fail:
2101         TALLOC_FREE(frame);
2102         return status;
2103 }
2104
2105 /****************************************************************************
2106  Close a file.
2107 ****************************************************************************/
2108
2109 struct cli_close_state {
2110         uint16_t vwv[3];
2111 };
2112
2113 static void cli_close_done(struct tevent_req *subreq);
2114
2115 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2116                                 struct event_context *ev,
2117                                 struct cli_state *cli,
2118                                 uint16_t fnum,
2119                                 struct tevent_req **psubreq)
2120 {
2121         struct tevent_req *req, *subreq;
2122         struct cli_close_state *state;
2123
2124         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2125         if (req == NULL) {
2126                 return NULL;
2127         }
2128
2129         SSVAL(state->vwv+0, 0, fnum);
2130         SIVALS(state->vwv+1, 0, -1);
2131
2132         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2133                                     0, NULL);
2134         if (subreq == NULL) {
2135                 TALLOC_FREE(req);
2136                 return NULL;
2137         }
2138         tevent_req_set_callback(subreq, cli_close_done, req);
2139         *psubreq = subreq;
2140         return req;
2141 }
2142
2143 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2144                                 struct event_context *ev,
2145                                 struct cli_state *cli,
2146                                 uint16_t fnum)
2147 {
2148         struct tevent_req *req, *subreq;
2149         NTSTATUS status;
2150
2151         req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2152         if (req == NULL) {
2153                 return NULL;
2154         }
2155
2156         status = cli_smb_req_send(subreq);
2157         if (tevent_req_nterror(req, status)) {
2158                 return tevent_req_post(req, ev);
2159         }
2160         return req;
2161 }
2162
2163 static void cli_close_done(struct tevent_req *subreq)
2164 {
2165         struct tevent_req *req = tevent_req_callback_data(
2166                 subreq, struct tevent_req);
2167         NTSTATUS status;
2168
2169         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2170         TALLOC_FREE(subreq);
2171         if (tevent_req_nterror(req, status)) {
2172                 return;
2173         }
2174         tevent_req_done(req);
2175 }
2176
2177 NTSTATUS cli_close_recv(struct tevent_req *req)
2178 {
2179         return tevent_req_simple_recv_ntstatus(req);
2180 }
2181
2182 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2183 {
2184         TALLOC_CTX *frame = talloc_stackframe();
2185         struct event_context *ev;
2186         struct tevent_req *req;
2187         NTSTATUS status = NT_STATUS_OK;
2188
2189         if (cli_has_async_calls(cli)) {
2190                 /*
2191                  * Can't use sync call while an async call is in flight
2192                  */
2193                 status = NT_STATUS_INVALID_PARAMETER;
2194                 goto fail;
2195         }
2196
2197         ev = event_context_init(frame);
2198         if (ev == NULL) {
2199                 status = NT_STATUS_NO_MEMORY;
2200                 goto fail;
2201         }
2202
2203         req = cli_close_send(frame, ev, cli, fnum);
2204         if (req == NULL) {
2205                 status = NT_STATUS_NO_MEMORY;
2206                 goto fail;
2207         }
2208
2209         if (!tevent_req_poll(req, ev)) {
2210                 status = map_nt_error_from_unix(errno);
2211                 goto fail;
2212         }
2213
2214         status = cli_close_recv(req);
2215  fail:
2216         TALLOC_FREE(frame);
2217         return status;
2218 }
2219
2220 /****************************************************************************
2221  Truncate a file to a specified size
2222 ****************************************************************************/
2223
2224 struct ftrunc_state {
2225         uint16_t setup;
2226         uint8_t param[6];
2227         uint8_t data[8];
2228 };
2229
2230 static void cli_ftruncate_done(struct tevent_req *subreq)
2231 {
2232         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2233                                          NULL, 0, NULL, NULL, 0, NULL);
2234         tevent_req_simple_finish_ntstatus(subreq, status);
2235 }
2236
2237 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2238                                         struct event_context *ev,
2239                                         struct cli_state *cli,
2240                                         uint16_t fnum,
2241                                         uint64_t size)
2242 {
2243         struct tevent_req *req = NULL, *subreq = NULL;
2244         struct ftrunc_state *state = NULL;
2245
2246         req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2247         if (req == NULL) {
2248                 return NULL;
2249         }
2250
2251         /* Setup setup word. */
2252         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2253
2254         /* Setup param array. */
2255         SSVAL(state->param,0,fnum);
2256         SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2257         SSVAL(state->param,4,0);
2258
2259         /* Setup data array. */
2260         SBVAL(state->data, 0, size);
2261
2262         subreq = cli_trans_send(state,                  /* mem ctx. */
2263                                 ev,                     /* event ctx. */
2264                                 cli,                    /* cli_state. */
2265                                 SMBtrans2,              /* cmd. */
2266                                 NULL,                   /* pipe name. */
2267                                 -1,                     /* fid. */
2268                                 0,                      /* function. */
2269                                 0,                      /* flags. */
2270                                 &state->setup,          /* setup. */
2271                                 1,                      /* num setup uint16_t words. */
2272                                 0,                      /* max returned setup. */
2273                                 state->param,           /* param. */
2274                                 6,                      /* num param. */
2275                                 2,                      /* max returned param. */
2276                                 state->data,            /* data. */
2277                                 8,                      /* num data. */
2278                                 0);                     /* max returned data. */
2279
2280         if (tevent_req_nomem(subreq, req)) {
2281                 return tevent_req_post(req, ev);
2282         }
2283         tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2284         return req;
2285 }
2286
2287 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2288 {
2289         return tevent_req_simple_recv_ntstatus(req);
2290 }
2291
2292 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2293 {
2294         TALLOC_CTX *frame = talloc_stackframe();
2295         struct event_context *ev = NULL;
2296         struct tevent_req *req = NULL;
2297         NTSTATUS status = NT_STATUS_OK;
2298
2299         if (cli_has_async_calls(cli)) {
2300                 /*
2301                  * Can't use sync call while an async call is in flight
2302                  */
2303                 status = NT_STATUS_INVALID_PARAMETER;
2304                 goto fail;
2305         }
2306
2307         ev = event_context_init(frame);
2308         if (ev == NULL) {
2309                 status = NT_STATUS_NO_MEMORY;
2310                 goto fail;
2311         }
2312
2313         req = cli_ftruncate_send(frame,
2314                                 ev,
2315                                 cli,
2316                                 fnum,
2317                                 size);
2318         if (req == NULL) {
2319                 status = NT_STATUS_NO_MEMORY;
2320                 goto fail;
2321         }
2322
2323         if (!tevent_req_poll(req, ev)) {
2324                 status = map_nt_error_from_unix(errno);
2325                 goto fail;
2326         }
2327
2328         status = cli_ftruncate_recv(req);
2329
2330  fail:
2331         TALLOC_FREE(frame);
2332         return status;
2333 }
2334
2335 /****************************************************************************
2336  send a lock with a specified locktype
2337  this is used for testing LOCKING_ANDX_CANCEL_LOCK
2338 ****************************************************************************/
2339
2340 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2341                       uint32_t offset, uint32_t len,
2342                       int timeout, unsigned char locktype)
2343 {
2344         uint16_t vwv[8];
2345         uint8_t bytes[10];
2346         NTSTATUS status;
2347         int saved_timeout;
2348
2349         SCVAL(vwv + 0, 0, 0xff);
2350         SCVAL(vwv + 0, 1, 0);
2351         SSVAL(vwv + 1, 0, 0);
2352         SSVAL(vwv + 2, 0, fnum);
2353         SCVAL(vwv + 3, 0, locktype);
2354         SCVAL(vwv + 3, 1, 0);
2355         SIVALS(vwv + 4, 0, timeout);
2356         SSVAL(vwv + 6, 0, 0);
2357         SSVAL(vwv + 7, 0, 1);
2358
2359         SSVAL(bytes, 0, cli->pid);
2360         SIVAL(bytes, 2, offset);
2361         SIVAL(bytes, 6, len);
2362
2363         saved_timeout = cli->timeout;
2364
2365         if (timeout != 0) {
2366                 cli->timeout = (timeout == -1)
2367                         ? 0x7FFFFFFF : (timeout + 2*1000);
2368         }
2369
2370         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2371                          10, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2372
2373         cli->timeout = saved_timeout;
2374
2375         return status;
2376 }
2377
2378 /****************************************************************************
2379  Lock a file.
2380  note that timeout is in units of 2 milliseconds
2381 ****************************************************************************/
2382
2383 bool cli_lock(struct cli_state *cli, uint16_t fnum,
2384                   uint32_t offset, uint32_t len, int timeout,
2385                   enum brl_type lock_type)
2386 {
2387         NTSTATUS status;
2388
2389         status = cli_locktype(cli, fnum, offset, len, timeout,
2390                               (lock_type == READ_LOCK? 1 : 0));
2391         return NT_STATUS_IS_OK(status);
2392 }
2393
2394 /****************************************************************************
2395  Unlock a file.
2396 ****************************************************************************/
2397
2398 struct cli_unlock_state {
2399         uint16_t vwv[8];
2400         uint8_t data[10];
2401 };
2402
2403 static void cli_unlock_done(struct tevent_req *subreq);
2404
2405 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
2406                                 struct event_context *ev,
2407                                 struct cli_state *cli,
2408                                 uint16_t fnum,
2409                                 uint64_t offset,
2410                                 uint64_t len)
2411
2412 {
2413         struct tevent_req *req = NULL, *subreq = NULL;
2414         struct cli_unlock_state *state = NULL;
2415         uint8_t additional_flags = 0;
2416
2417         req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
2418         if (req == NULL) {
2419                 return NULL;
2420         }
2421
2422         SCVAL(state->vwv+0, 0, 0xFF);
2423         SSVAL(state->vwv+2, 0, fnum);
2424         SCVAL(state->vwv+3, 0, 0);
2425         SIVALS(state->vwv+4, 0, 0);
2426         SSVAL(state->vwv+6, 0, 1);
2427         SSVAL(state->vwv+7, 0, 0);
2428
2429         SSVAL(state->data, 0, cli->pid);
2430         SIVAL(state->data, 2, offset);
2431         SIVAL(state->data, 6, len);
2432
2433         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2434                                 8, state->vwv, 10, state->data);
2435         if (tevent_req_nomem(subreq, req)) {
2436                 return tevent_req_post(req, ev);
2437         }
2438         tevent_req_set_callback(subreq, cli_unlock_done, req);
2439         return req;
2440 }
2441
2442 static void cli_unlock_done(struct tevent_req *subreq)
2443 {
2444         struct tevent_req *req = tevent_req_callback_data(
2445                                 subreq, struct tevent_req);
2446         NTSTATUS status;
2447
2448         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2449         TALLOC_FREE(subreq);
2450         if (tevent_req_nterror(req, status)) {
2451                 return;
2452         }
2453         tevent_req_done(req);
2454 }
2455
2456 NTSTATUS cli_unlock_recv(struct tevent_req *req)
2457 {
2458         return tevent_req_simple_recv_ntstatus(req);
2459 }
2460
2461 NTSTATUS cli_unlock(struct cli_state *cli,
2462                         uint16_t fnum,
2463                         uint32_t offset,
2464                         uint32_t len)
2465 {
2466         TALLOC_CTX *frame = talloc_stackframe();
2467         struct event_context *ev;
2468         struct tevent_req *req;
2469         NTSTATUS status = NT_STATUS_OK;
2470
2471         if (cli_has_async_calls(cli)) {
2472                 /*
2473                  * Can't use sync call while an async call is in flight
2474                  */
2475                 status = NT_STATUS_INVALID_PARAMETER;
2476                 goto fail;
2477         }
2478
2479         ev = event_context_init(frame);
2480         if (ev == NULL) {
2481                 status = NT_STATUS_NO_MEMORY;
2482                 goto fail;
2483         }
2484
2485         req = cli_unlock_send(frame, ev, cli,
2486                         fnum, offset, len);
2487         if (req == NULL) {
2488                 status = NT_STATUS_NO_MEMORY;
2489                 goto fail;
2490         }
2491
2492         if (!tevent_req_poll(req, ev)) {
2493                 status = map_nt_error_from_unix(errno);
2494                 goto fail;
2495         }
2496
2497         status = cli_unlock_recv(req);
2498
2499  fail:
2500         TALLOC_FREE(frame);
2501         return status;
2502 }
2503
2504 /****************************************************************************
2505  Lock a file with 64 bit offsets.
2506 ****************************************************************************/
2507
2508 bool cli_lock64(struct cli_state *cli, uint16_t fnum,
2509                 uint64_t offset, uint64_t len, int timeout,
2510                 enum brl_type lock_type)
2511 {
2512         uint16_t vwv[8];
2513         uint8_t bytes[20];
2514         int saved_timeout = cli->timeout;
2515         int ltype;
2516         NTSTATUS status;
2517
2518         if (! (cli->capabilities & CAP_LARGE_FILES)) {
2519                 return cli_lock(cli, fnum, offset, len, timeout, lock_type);
2520         }
2521
2522         ltype = (lock_type == READ_LOCK? 1 : 0);
2523         ltype |= LOCKING_ANDX_LARGE_FILES;
2524
2525         SCVAL(vwv + 0, 0, 0xff);
2526         SCVAL(vwv + 0, 1, 0);
2527         SSVAL(vwv + 1, 0, 0);
2528         SSVAL(vwv + 2, 0, fnum);
2529         SCVAL(vwv + 3, 0, ltype);
2530         SCVAL(vwv + 3, 1, 0);
2531         SIVALS(vwv + 4, 0, timeout);
2532         SSVAL(vwv + 6, 0, 0);
2533         SSVAL(vwv + 7, 0, 1);
2534
2535         SIVAL(bytes, 0, cli->pid);
2536         SOFF_T_R(bytes, 4, offset);
2537         SOFF_T_R(bytes, 12, len);
2538
2539         saved_timeout = cli->timeout;
2540
2541         if (timeout != 0) {
2542                 cli->timeout = (timeout == -1)
2543                         ? 0x7FFFFFFF : (timeout + 2*1000);
2544         }
2545
2546         status = cli_smb(talloc_tos(), cli, SMBlockingX, 0, 8, vwv,
2547                          20, bytes, NULL, 0, NULL, NULL, NULL, NULL);
2548
2549         cli->timeout = saved_timeout;
2550
2551         return NT_STATUS_IS_OK(status);
2552 }
2553
2554 /****************************************************************************
2555  Unlock a file with 64 bit offsets.
2556 ****************************************************************************/
2557
2558 struct cli_unlock64_state {
2559         uint16_t vwv[8];
2560         uint8_t data[20];
2561 };
2562
2563 static void cli_unlock64_done(struct tevent_req *subreq);
2564
2565 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
2566                                 struct event_context *ev,
2567                                 struct cli_state *cli,
2568                                 uint16_t fnum,
2569                                 uint64_t offset,
2570                                 uint64_t len)
2571
2572 {
2573         struct tevent_req *req = NULL, *subreq = NULL;
2574         struct cli_unlock64_state *state = NULL;
2575         uint8_t additional_flags = 0;
2576
2577         req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
2578         if (req == NULL) {
2579                 return NULL;
2580         }
2581
2582         SCVAL(state->vwv+0, 0, 0xff);
2583         SSVAL(state->vwv+2, 0, fnum);
2584         SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
2585         SIVALS(state->vwv+4, 0, 0);
2586         SSVAL(state->vwv+6, 0, 1);
2587         SSVAL(state->vwv+7, 0, 0);
2588
2589         SIVAL(state->data, 0, cli->pid);
2590         SOFF_T_R(state->data, 4, offset);
2591         SOFF_T_R(state->data, 12, len);
2592
2593         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2594                                 8, state->vwv, 20, state->data);
2595         if (tevent_req_nomem(subreq, req)) {
2596                 return tevent_req_post(req, ev);
2597         }
2598         tevent_req_set_callback(subreq, cli_unlock64_done, req);
2599         return req;
2600 }
2601
2602 static void cli_unlock64_done(struct tevent_req *subreq)
2603 {
2604         struct tevent_req *req = tevent_req_callback_data(
2605                                 subreq, struct tevent_req);
2606         NTSTATUS status;
2607
2608         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2609         TALLOC_FREE(subreq);
2610         if (tevent_req_nterror(req, status)) {
2611                 return;
2612         }
2613         tevent_req_done(req);
2614 }
2615
2616 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
2617 {
2618         return tevent_req_simple_recv_ntstatus(req);
2619 }
2620
2621 NTSTATUS cli_unlock64(struct cli_state *cli,
2622                                 uint16_t fnum,
2623                                 uint64_t offset,
2624                                 uint64_t len)
2625 {
2626         TALLOC_CTX *frame = talloc_stackframe();
2627         struct event_context *ev;
2628         struct tevent_req *req;
2629         NTSTATUS status = NT_STATUS_OK;
2630
2631         if (! (cli->capabilities & CAP_LARGE_FILES)) {
2632                 return cli_unlock(cli, fnum, offset, len);
2633         }
2634
2635         if (cli_has_async_calls(cli)) {
2636                 /*
2637                  * Can't use sync call while an async call is in flight
2638                  */
2639                 status = NT_STATUS_INVALID_PARAMETER;
2640                 goto fail;
2641         }
2642
2643         ev = event_context_init(frame);
2644         if (ev == NULL) {
2645                 status = NT_STATUS_NO_MEMORY;
2646                 goto fail;
2647         }
2648
2649         req = cli_unlock64_send(frame, ev, cli,
2650                         fnum, offset, len);
2651         if (req == NULL) {
2652                 status = NT_STATUS_NO_MEMORY;
2653                 goto fail;
2654         }
2655
2656         if (!tevent_req_poll(req, ev)) {
2657                 status = map_nt_error_from_unix(errno);
2658                 goto fail;
2659         }
2660
2661         status = cli_unlock64_recv(req);
2662
2663  fail:
2664         TALLOC_FREE(frame);
2665         return status;
2666 }
2667
2668 /****************************************************************************
2669  Get/unlock a POSIX lock on a file - internal function.
2670 ****************************************************************************/
2671
2672 struct posix_lock_state {
2673         uint16_t setup;
2674         uint8_t param[4];
2675         uint8_t data[POSIX_LOCK_DATA_SIZE];
2676 };
2677
2678 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
2679 {
2680         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
2681                                          NULL, 0, NULL, NULL, 0, NULL);
2682         tevent_req_simple_finish_ntstatus(subreq, status);
2683 }
2684
2685 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
2686                                         struct event_context *ev,
2687                                         struct cli_state *cli,
2688                                         uint16_t fnum,
2689                                         uint64_t offset,
2690                                         uint64_t len,
2691                                         bool wait_lock,
2692                                         enum brl_type lock_type)
2693 {
2694         struct tevent_req *req = NULL, *subreq = NULL;
2695         struct posix_lock_state *state = NULL;
2696
2697         req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
2698         if (req == NULL) {
2699                 return NULL;
2700         }
2701
2702         /* Setup setup word. */
2703         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2704
2705         /* Setup param array. */
2706         SSVAL(&state->param, 0, fnum);
2707         SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
2708
2709         /* Setup data array. */
2710         switch (lock_type) {
2711                 case READ_LOCK:
2712                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2713                                 POSIX_LOCK_TYPE_READ);
2714                         break;
2715                 case WRITE_LOCK:
2716                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2717                                 POSIX_LOCK_TYPE_WRITE);
2718                         break;
2719                 case UNLOCK_LOCK:
2720                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
2721                                 POSIX_LOCK_TYPE_UNLOCK);
2722                         break;
2723                 default:
2724                         return NULL;
2725         }
2726
2727         if (wait_lock) {
2728                 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
2729                                 POSIX_LOCK_FLAG_WAIT);
2730         } else {
2731                 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
2732                                 POSIX_LOCK_FLAG_NOWAIT);
2733         }
2734
2735         SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli->pid);
2736         SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
2737         SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
2738
2739         subreq = cli_trans_send(state,                  /* mem ctx. */
2740                                 ev,                     /* event ctx. */
2741                                 cli,                    /* cli_state. */
2742                                 SMBtrans2,              /* cmd. */
2743                                 NULL,                   /* pipe name. */
2744                                 -1,                     /* fid. */
2745                                 0,                      /* function. */
2746                                 0,                      /* flags. */
2747                                 &state->setup,          /* setup. */
2748                                 1,                      /* num setup uint16_t words. */
2749                                 0,                      /* max returned setup. */
2750                                 state->param,           /* param. */
2751                                 4,                      /* num param. */
2752                                 2,                      /* max returned param. */
2753                                 state->data,            /* data. */
2754                                 POSIX_LOCK_DATA_SIZE,   /* num data. */
2755                                 0);                     /* max returned data. */
2756
2757         if (tevent_req_nomem(subreq, req)) {
2758                 return tevent_req_post(req, ev);
2759         }
2760         tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
2761         return req;
2762 }
2763
2764 /****************************************************************************
2765  POSIX Lock a file.
2766 ****************************************************************************/
2767
2768 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
2769                                         struct event_context *ev,
2770                                         struct cli_state *cli,
2771                                         uint16_t fnum,
2772                                         uint64_t offset,
2773                                         uint64_t len,
2774                                         bool wait_lock,
2775                                         enum brl_type lock_type)
2776 {
2777         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
2778                                         wait_lock, lock_type);
2779 }
2780
2781 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
2782 {
2783         return tevent_req_simple_recv_ntstatus(req);
2784 }
2785
2786 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
2787                         uint64_t offset, uint64_t len,
2788                         bool wait_lock, enum brl_type lock_type)
2789 {
2790         TALLOC_CTX *frame = talloc_stackframe();
2791         struct event_context *ev = NULL;
2792         struct tevent_req *req = NULL;
2793         NTSTATUS status = NT_STATUS_OK;
2794
2795         if (cli_has_async_calls(cli)) {
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         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
2804                 status = NT_STATUS_INVALID_PARAMETER;
2805                 goto fail;
2806         }
2807
2808         ev = event_context_init(frame);
2809         if (ev == NULL) {
2810                 status = NT_STATUS_NO_MEMORY;
2811                 goto fail;
2812         }
2813
2814         req = cli_posix_lock_send(frame,
2815                                 ev,
2816                                 cli,
2817                                 fnum,
2818                                 offset,
2819                                 len,
2820                                 wait_lock,
2821                                 lock_type);
2822         if (req == NULL) {
2823                 status = NT_STATUS_NO_MEMORY;
2824                 goto fail;
2825         }
2826
2827         if (!tevent_req_poll(req, ev)) {
2828                 status = map_nt_error_from_unix(errno);
2829                 goto fail;
2830         }
2831
2832         status = cli_posix_lock_recv(req);
2833
2834  fail:
2835         TALLOC_FREE(frame);
2836         return status;
2837 }
2838
2839 /****************************************************************************
2840  POSIX Unlock a file.
2841 ****************************************************************************/
2842
2843 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
2844                                         struct event_context *ev,
2845                                         struct cli_state *cli,
2846                                         uint16_t fnum,
2847                                         uint64_t offset,
2848                                         uint64_t len)
2849 {
2850         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
2851                                         false, UNLOCK_LOCK);
2852 }
2853
2854 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
2855 {
2856         return tevent_req_simple_recv_ntstatus(req);
2857 }
2858
2859 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
2860 {
2861         TALLOC_CTX *frame = talloc_stackframe();
2862         struct event_context *ev = NULL;
2863         struct tevent_req *req = NULL;
2864         NTSTATUS status = NT_STATUS_OK;
2865
2866         if (cli_has_async_calls(cli)) {
2867                 /*
2868                  * Can't use sync call while an async call is in flight
2869                  */
2870                 status = NT_STATUS_INVALID_PARAMETER;
2871                 goto fail;
2872         }
2873
2874         ev = event_context_init(frame);
2875         if (ev == NULL) {
2876                 status = NT_STATUS_NO_MEMORY;
2877                 goto fail;
2878         }
2879
2880         req = cli_posix_unlock_send(frame,
2881                                 ev,
2882                                 cli,
2883                                 fnum,
2884                                 offset,
2885                                 len);
2886         if (req == NULL) {
2887                 status = NT_STATUS_NO_MEMORY;
2888                 goto fail;
2889         }
2890
2891         if (!tevent_req_poll(req, ev)) {
2892                 status = map_nt_error_from_unix(errno);
2893                 goto fail;
2894         }
2895
2896         status = cli_posix_unlock_recv(req);
2897
2898  fail:
2899         TALLOC_FREE(frame);
2900         return status;
2901 }
2902
2903 /****************************************************************************
2904  Do a SMBgetattrE call.
2905 ****************************************************************************/
2906
2907 static void cli_getattrE_done(struct tevent_req *subreq);
2908
2909 struct cli_getattrE_state {
2910         uint16_t vwv[1];
2911         int zone_offset;
2912         uint16_t attr;
2913         SMB_OFF_T size;
2914         time_t change_time;
2915         time_t access_time;
2916         time_t write_time;
2917 };
2918
2919 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
2920                                 struct event_context *ev,
2921                                 struct cli_state *cli,
2922                                 uint16_t fnum)
2923 {
2924         struct tevent_req *req = NULL, *subreq = NULL;
2925         struct cli_getattrE_state *state = NULL;
2926         uint8_t additional_flags = 0;
2927
2928         req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
2929         if (req == NULL) {
2930                 return NULL;
2931         }
2932
2933         state->zone_offset = cli->serverzone;
2934         SSVAL(state->vwv+0,0,fnum);
2935
2936         subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
2937                               1, state->vwv, 0, NULL);
2938         if (tevent_req_nomem(subreq, req)) {
2939                 return tevent_req_post(req, ev);
2940         }
2941         tevent_req_set_callback(subreq, cli_getattrE_done, req);
2942         return req;
2943 }
2944
2945 static void cli_getattrE_done(struct tevent_req *subreq)
2946 {
2947         struct tevent_req *req = tevent_req_callback_data(
2948                 subreq, struct tevent_req);
2949         struct cli_getattrE_state *state = tevent_req_data(
2950                 req, struct cli_getattrE_state);
2951         uint8_t wct;
2952         uint16_t *vwv = NULL;
2953         uint8_t *inbuf;
2954         NTSTATUS status;
2955
2956         status = cli_smb_recv(subreq, state, &inbuf, 11, &wct, &vwv,
2957                               NULL, NULL);
2958         TALLOC_FREE(subreq);
2959         if (tevent_req_nterror(req, status)) {
2960                 return;
2961         }
2962
2963         state->size = (SMB_OFF_T)IVAL(vwv+6,0);
2964         state->attr = SVAL(vwv+10,0);
2965         state->change_time = make_unix_date2(vwv+0, state->zone_offset);
2966         state->access_time = make_unix_date2(vwv+2, state->zone_offset);
2967         state->write_time = make_unix_date2(vwv+4, state->zone_offset);
2968
2969         tevent_req_done(req);
2970 }
2971
2972 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
2973                         uint16_t *attr,
2974                         SMB_OFF_T *size,
2975                         time_t *change_time,
2976                         time_t *access_time,
2977                         time_t *write_time)
2978 {
2979         struct cli_getattrE_state *state = tevent_req_data(
2980                                 req, struct cli_getattrE_state);
2981         NTSTATUS status;
2982
2983         if (tevent_req_is_nterror(req, &status)) {
2984                 return status;
2985         }
2986         if (attr) {
2987                 *attr = state->attr;
2988         }
2989         if (size) {
2990                 *size = state->size;
2991         }
2992         if (change_time) {
2993                 *change_time = state->change_time;
2994         }
2995         if (access_time) {
2996                 *access_time = state->access_time;
2997         }
2998         if (write_time) {
2999                 *write_time = state->write_time;
3000         }
3001         return NT_STATUS_OK;
3002 }
3003
3004 NTSTATUS cli_getattrE(struct cli_state *cli,
3005                         uint16_t fnum,
3006                         uint16_t *attr,
3007                         SMB_OFF_T *size,
3008                         time_t *change_time,
3009                         time_t *access_time,
3010                         time_t *write_time)
3011 {
3012         TALLOC_CTX *frame = talloc_stackframe();
3013         struct event_context *ev = NULL;
3014         struct tevent_req *req = NULL;
3015         NTSTATUS status = NT_STATUS_OK;
3016
3017         if (cli_has_async_calls(cli)) {
3018                 /*
3019                  * Can't use sync call while an async call is in flight
3020                  */
3021                 status = NT_STATUS_INVALID_PARAMETER;
3022                 goto fail;
3023         }
3024
3025         ev = event_context_init(frame);
3026         if (ev == NULL) {
3027                 status = NT_STATUS_NO_MEMORY;
3028                 goto fail;
3029         }
3030
3031         req = cli_getattrE_send(frame, ev, cli, fnum);
3032         if (req == NULL) {
3033                 status = NT_STATUS_NO_MEMORY;
3034                 goto fail;
3035         }
3036
3037         if (!tevent_req_poll(req, ev)) {
3038                 status = map_nt_error_from_unix(errno);
3039                 goto fail;
3040         }
3041
3042         status = cli_getattrE_recv(req,
3043                                         attr,
3044                                         size,
3045                                         change_time,
3046                                         access_time,
3047                                         write_time);
3048
3049  fail:
3050         TALLOC_FREE(frame);
3051         return status;
3052 }
3053
3054 /****************************************************************************
3055  Do a SMBgetatr call
3056 ****************************************************************************/
3057
3058 static void cli_getatr_done(struct tevent_req *subreq);
3059
3060 struct cli_getatr_state {
3061         int zone_offset;
3062         uint16_t attr;
3063         SMB_OFF_T size;
3064         time_t write_time;
3065 };
3066
3067 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3068                                 struct event_context *ev,
3069                                 struct cli_state *cli,
3070                                 const char *fname)
3071 {
3072         struct tevent_req *req = NULL, *subreq = NULL;
3073         struct cli_getatr_state *state = NULL;
3074         uint8_t additional_flags = 0;
3075         uint8_t *bytes = NULL;
3076
3077         req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3078         if (req == NULL) {
3079                 return NULL;
3080         }
3081
3082         state->zone_offset = cli->serverzone;
3083
3084         bytes = talloc_array(state, uint8_t, 1);
3085         if (tevent_req_nomem(bytes, req)) {
3086                 return tevent_req_post(req, ev);
3087         }
3088         bytes[0] = 4;
3089         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3090                                    strlen(fname)+1, NULL);
3091
3092         if (tevent_req_nomem(bytes, req)) {
3093                 return tevent_req_post(req, ev);
3094         }
3095
3096         subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3097                               0, NULL, talloc_get_size(bytes), bytes);
3098         if (tevent_req_nomem(subreq, req)) {
3099                 return tevent_req_post(req, ev);
3100         }
3101         tevent_req_set_callback(subreq, cli_getatr_done, req);
3102         return req;
3103 }
3104
3105 static void cli_getatr_done(struct tevent_req *subreq)
3106 {
3107         struct tevent_req *req = tevent_req_callback_data(
3108                 subreq, struct tevent_req);
3109         struct cli_getatr_state *state = tevent_req_data(
3110                 req, struct cli_getatr_state);
3111         uint8_t wct;
3112         uint16_t *vwv = NULL;
3113         uint8_t *inbuf;
3114         NTSTATUS status;
3115
3116         status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3117                               NULL);
3118         TALLOC_FREE(subreq);
3119         if (tevent_req_nterror(req, status)) {
3120                 return;
3121         }
3122
3123         state->attr = SVAL(vwv+0,0);
3124         state->size = (SMB_OFF_T)IVAL(vwv+3,0);
3125         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3126
3127         tevent_req_done(req);
3128 }
3129
3130 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3131                         uint16_t *attr,
3132                         SMB_OFF_T *size,
3133                         time_t *write_time)
3134 {
3135         struct cli_getatr_state *state = tevent_req_data(
3136                                 req, struct cli_getatr_state);
3137         NTSTATUS status;
3138
3139         if (tevent_req_is_nterror(req, &status)) {
3140                 return status;
3141         }
3142         if (attr) {
3143                 *attr = state->attr;
3144         }
3145         if (size) {
3146                 *size = state->size;
3147         }
3148         if (write_time) {
3149                 *write_time = state->write_time;
3150         }
3151         return NT_STATUS_OK;
3152 }
3153
3154 NTSTATUS cli_getatr(struct cli_state *cli,
3155                         const char *fname,
3156                         uint16_t *attr,
3157                         SMB_OFF_T *size,
3158                         time_t *write_time)
3159 {
3160         TALLOC_CTX *frame = talloc_stackframe();
3161         struct event_context *ev = NULL;
3162         struct tevent_req *req = NULL;
3163         NTSTATUS status = NT_STATUS_OK;
3164
3165         if (cli_has_async_calls(cli)) {
3166                 /*
3167                  * Can't use sync call while an async call is in flight
3168                  */
3169                 status = NT_STATUS_INVALID_PARAMETER;
3170                 goto fail;
3171         }
3172
3173         ev = event_context_init(frame);
3174         if (ev == NULL) {
3175                 status = NT_STATUS_NO_MEMORY;
3176                 goto fail;
3177         }
3178
3179         req = cli_getatr_send(frame, ev, cli, fname);
3180         if (req == NULL) {
3181                 status = NT_STATUS_NO_MEMORY;
3182                 goto fail;
3183         }
3184
3185         if (!tevent_req_poll(req, ev)) {
3186                 status = map_nt_error_from_unix(errno);
3187                 goto fail;
3188         }
3189
3190         status = cli_getatr_recv(req,
3191                                 attr,
3192                                 size,
3193                                 write_time);
3194
3195  fail:
3196         TALLOC_FREE(frame);
3197         return status;
3198 }
3199
3200 /****************************************************************************
3201  Do a SMBsetattrE call.
3202 ****************************************************************************/
3203
3204 static void cli_setattrE_done(struct tevent_req *subreq);
3205
3206 struct cli_setattrE_state {
3207         uint16_t vwv[7];
3208 };
3209
3210 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3211                                 struct event_context *ev,
3212                                 struct cli_state *cli,
3213                                 uint16_t fnum,
3214                                 time_t change_time,
3215                                 time_t access_time,
3216                                 time_t write_time)
3217 {
3218         struct tevent_req *req = NULL, *subreq = NULL;
3219         struct cli_setattrE_state *state = NULL;
3220         uint8_t additional_flags = 0;
3221
3222         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3223         if (req == NULL) {
3224                 return NULL;
3225         }
3226
3227         SSVAL(state->vwv+0, 0, fnum);
3228         push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
3229                        cli->serverzone);
3230         push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
3231                        cli->serverzone);
3232         push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
3233                        cli->serverzone);
3234
3235         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3236                               7, state->vwv, 0, NULL);
3237         if (tevent_req_nomem(subreq, req)) {
3238                 return tevent_req_post(req, ev);
3239         }
3240         tevent_req_set_callback(subreq, cli_setattrE_done, req);
3241         return req;
3242 }
3243
3244 static void cli_setattrE_done(struct tevent_req *subreq)
3245 {
3246         struct tevent_req *req = tevent_req_callback_data(
3247                 subreq, struct tevent_req);
3248         NTSTATUS status;
3249
3250         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3251         TALLOC_FREE(subreq);
3252         if (tevent_req_nterror(req, status)) {
3253                 return;
3254         }
3255         tevent_req_done(req);
3256 }
3257
3258 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3259 {
3260         return tevent_req_simple_recv_ntstatus(req);
3261 }
3262
3263 NTSTATUS cli_setattrE(struct cli_state *cli,
3264                         uint16_t fnum,
3265                         time_t change_time,
3266                         time_t access_time,
3267                         time_t write_time)
3268 {
3269         TALLOC_CTX *frame = talloc_stackframe();
3270         struct event_context *ev = NULL;
3271         struct tevent_req *req = NULL;
3272         NTSTATUS status = NT_STATUS_OK;
3273
3274         if (cli_has_async_calls(cli)) {
3275                 /*
3276                  * Can't use sync call while an async call is in flight
3277                  */
3278                 status = NT_STATUS_INVALID_PARAMETER;
3279                 goto fail;
3280         }
3281
3282         ev = event_context_init(frame);
3283         if (ev == NULL) {
3284                 status = NT_STATUS_NO_MEMORY;
3285                 goto fail;
3286         }
3287
3288         req = cli_setattrE_send(frame, ev,
3289                         cli,
3290                         fnum,
3291                         change_time,
3292                         access_time,
3293                         write_time);
3294
3295         if (req == NULL) {
3296                 status = NT_STATUS_NO_MEMORY;
3297                 goto fail;
3298         }
3299
3300         if (!tevent_req_poll(req, ev)) {
3301                 status = map_nt_error_from_unix(errno);
3302                 goto fail;
3303         }
3304
3305         status = cli_setattrE_recv(req);
3306
3307  fail:
3308         TALLOC_FREE(frame);
3309         return status;
3310 }
3311
3312 /****************************************************************************
3313  Do a SMBsetatr call.
3314 ****************************************************************************/
3315
3316 static void cli_setatr_done(struct tevent_req *subreq);
3317
3318 struct cli_setatr_state {
3319         uint16_t vwv[8];
3320 };
3321
3322 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3323                                 struct event_context *ev,
3324                                 struct cli_state *cli,
3325                                 const char *fname,
3326                                 uint16_t attr,
3327                                 time_t mtime)
3328 {
3329         struct tevent_req *req = NULL, *subreq = NULL;
3330         struct cli_setatr_state *state = NULL;
3331         uint8_t additional_flags = 0;
3332         uint8_t *bytes = NULL;
3333
3334         req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3335         if (req == NULL) {
3336                 return NULL;
3337         }
3338
3339         SSVAL(state->vwv+0, 0, attr);
3340         push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, cli->serverzone);
3341
3342         bytes = talloc_array(state, uint8_t, 1);
3343         if (tevent_req_nomem(bytes, req)) {
3344                 return tevent_req_post(req, ev);
3345         }
3346         bytes[0] = 4;
3347         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3348                                    strlen(fname)+1, NULL);
3349         if (tevent_req_nomem(bytes, req)) {
3350                 return tevent_req_post(req, ev);
3351         }
3352         bytes = talloc_realloc(state, bytes, uint8_t,
3353                         talloc_get_size(bytes)+1);
3354         if (tevent_req_nomem(bytes, req)) {
3355                 return tevent_req_post(req, ev);
3356         }
3357
3358         bytes[talloc_get_size(bytes)-1] = 4;
3359         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",
3360                                    1, NULL);
3361         if (tevent_req_nomem(bytes, req)) {
3362                 return tevent_req_post(req, ev);
3363         }
3364
3365         subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3366                               8, state->vwv, talloc_get_size(bytes), bytes);
3367         if (tevent_req_nomem(subreq, req)) {
3368                 return tevent_req_post(req, ev);
3369         }
3370         tevent_req_set_callback(subreq, cli_setatr_done, req);
3371         return req;
3372 }
3373
3374 static void cli_setatr_done(struct tevent_req *subreq)
3375 {
3376         struct tevent_req *req = tevent_req_callback_data(
3377                 subreq, struct tevent_req);
3378         NTSTATUS status;
3379
3380         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3381         TALLOC_FREE(subreq);
3382         if (tevent_req_nterror(req, status)) {
3383                 return;
3384         }
3385         tevent_req_done(req);
3386 }
3387
3388 NTSTATUS cli_setatr_recv(struct tevent_req *req)
3389 {
3390         return tevent_req_simple_recv_ntstatus(req);
3391 }
3392
3393 NTSTATUS cli_setatr(struct cli_state *cli,
3394                 const char *fname,
3395                 uint16_t attr,
3396                 time_t mtime)
3397 {
3398         TALLOC_CTX *frame = talloc_stackframe();
3399         struct event_context *ev = NULL;
3400         struct tevent_req *req = NULL;
3401         NTSTATUS status = NT_STATUS_OK;
3402
3403         if (cli_has_async_calls(cli)) {
3404                 /*
3405                  * Can't use sync call while an async call is in flight
3406                  */
3407                 status = NT_STATUS_INVALID_PARAMETER;
3408                 goto fail;
3409         }
3410
3411         ev = event_context_init(frame);
3412         if (ev == NULL) {
3413                 status = NT_STATUS_NO_MEMORY;
3414                 goto fail;
3415         }
3416
3417         req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
3418         if (req == NULL) {
3419                 status = NT_STATUS_NO_MEMORY;
3420                 goto fail;
3421         }
3422
3423         if (!tevent_req_poll(req, ev)) {
3424                 status = map_nt_error_from_unix(errno);
3425                 goto fail;
3426         }
3427
3428         status = cli_setatr_recv(req);
3429
3430  fail:
3431         TALLOC_FREE(frame);
3432         return status;
3433 }
3434
3435 /****************************************************************************
3436  Check for existance of a dir.
3437 ****************************************************************************/
3438
3439 static void cli_chkpath_done(struct tevent_req *subreq);
3440
3441 struct cli_chkpath_state {
3442         int dummy;
3443 };
3444
3445 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
3446                                   struct event_context *ev,
3447                                   struct cli_state *cli,
3448                                   const char *fname)
3449 {
3450         struct tevent_req *req = NULL, *subreq = NULL;
3451         struct cli_chkpath_state *state = NULL;
3452         uint8_t additional_flags = 0;
3453         uint8_t *bytes = NULL;
3454
3455         req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
3456         if (req == NULL) {
3457                 return NULL;
3458         }
3459
3460         bytes = talloc_array(state, uint8_t, 1);
3461         if (tevent_req_nomem(bytes, req)) {
3462                 return tevent_req_post(req, ev);
3463         }
3464         bytes[0] = 4;
3465         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3466                                    strlen(fname)+1, NULL);
3467
3468         if (tevent_req_nomem(bytes, req)) {
3469                 return tevent_req_post(req, ev);
3470         }
3471
3472         subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
3473                               0, NULL, talloc_get_size(bytes), bytes);
3474         if (tevent_req_nomem(subreq, req)) {
3475               &nb