8b76e8f5d8b8c7190cf5edcb4d1d0cec90ba1146
[sfrench/samba-autobuild/.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "libsmb/libsmb.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "async_smb.h"
26 #include "libsmb/clirap.h"
27 #include "trans2.h"
28 #include "ntioctl.h"
29
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                 return tevent_req_post(req, ev);
3476         }
3477         tevent_req_set_callback(subreq, cli_chkpath_done, req);
3478         return req;
3479 }
3480
3481 static void cli_chkpath_done(struct tevent_req *subreq)
3482 {
3483         struct tevent_req *req = tevent_req_callback_data(
3484                 subreq, struct tevent_req);
3485         NTSTATUS status;
3486
3487         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3488         TALLOC_FREE(subreq);
3489         if (tevent_req_nterror(req, status)) {
3490                 return;
3491         }
3492         tevent_req_done(req);
3493 }
3494
3495 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
3496 {
3497         return tevent_req_simple_recv_ntstatus(req);
3498 }
3499
3500 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
3501 {
3502         TALLOC_CTX *frame = talloc_stackframe();
3503         struct event_context *ev = NULL;
3504         struct tevent_req *req = NULL;
3505         char *path2 = NULL;
3506         NTSTATUS status = NT_STATUS_OK;
3507
3508         if (cli_has_async_calls(cli)) {
3509                 /*
3510                  * Can't use sync call while an async call is in flight
3511                  */
3512                 status = NT_STATUS_INVALID_PARAMETER;
3513                 goto fail;
3514         }
3515
3516         path2 = talloc_strdup(frame, path);
3517         if (!path2) {
3518                 status = NT_STATUS_NO_MEMORY;
3519                 goto fail;
3520         }
3521         trim_char(path2,'\0','\\');
3522         if (!*path2) {
3523                 path2 = talloc_strdup(frame, "\\");
3524                 if (!path2) {
3525                         status = NT_STATUS_NO_MEMORY;
3526                         goto fail;
3527                 }
3528         }
3529
3530         ev = event_context_init(frame);
3531         if (ev == NULL) {
3532                 status = NT_STATUS_NO_MEMORY;
3533                 goto fail;
3534         }
3535
3536         req = cli_chkpath_send(frame, ev, cli, path2);
3537         if (req == NULL) {
3538                 status = NT_STATUS_NO_MEMORY;
3539                 goto fail;
3540         }
3541
3542         if (!tevent_req_poll(req, ev)) {
3543                 status = map_nt_error_from_unix(errno);
3544                 goto fail;
3545         }
3546
3547         status = cli_chkpath_recv(req);
3548
3549  fail:
3550         TALLOC_FREE(frame);
3551         return status;
3552 }
3553
3554 /****************************************************************************
3555  Query disk space.
3556 ****************************************************************************/
3557
3558 static void cli_dskattr_done(struct tevent_req *subreq);
3559
3560 struct cli_dskattr_state {
3561         int bsize;
3562         int total;
3563         int avail;
3564 };
3565
3566 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
3567                                   struct event_context *ev,
3568                                   struct cli_state *cli)
3569 {
3570         struct tevent_req *req = NULL, *subreq = NULL;
3571         struct cli_dskattr_state *state = NULL;
3572         uint8_t additional_flags = 0;
3573
3574         req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
3575         if (req == NULL) {
3576                 return NULL;
3577         }
3578
3579         subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
3580                               0, NULL, 0, NULL);
3581         if (tevent_req_nomem(subreq, req)) {
3582                 return tevent_req_post(req, ev);
3583         }
3584         tevent_req_set_callback(subreq, cli_dskattr_done, req);
3585         return req;
3586 }
3587
3588 static void cli_dskattr_done(struct tevent_req *subreq)
3589 {
3590         struct tevent_req *req = tevent_req_callback_data(
3591                 subreq, struct tevent_req);
3592         struct cli_dskattr_state *state = tevent_req_data(
3593                 req, struct cli_dskattr_state);
3594         uint8_t wct;
3595         uint16_t *vwv = NULL;
3596         uint8_t *inbuf;
3597         NTSTATUS status;
3598
3599         status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3600                               NULL);
3601         TALLOC_FREE(subreq);
3602         if (tevent_req_nterror(req, status)) {
3603                 return;
3604         }
3605         state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
3606         state->total = SVAL(vwv+0, 0);
3607         state->avail = SVAL(vwv+3, 0);
3608         tevent_req_done(req);
3609 }
3610
3611 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
3612 {
3613         struct cli_dskattr_state *state = tevent_req_data(
3614                                 req, struct cli_dskattr_state);
3615         NTSTATUS status;
3616
3617         if (tevent_req_is_nterror(req, &status)) {
3618                 return status;
3619         }
3620         *bsize = state->bsize;
3621         *total = state->total;
3622         *avail = state->avail;
3623         return NT_STATUS_OK;
3624 }
3625
3626 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3627 {
3628         TALLOC_CTX *frame = talloc_stackframe();
3629         struct event_context *ev = NULL;
3630         struct tevent_req *req = NULL;
3631         NTSTATUS status = NT_STATUS_OK;
3632
3633         if (cli_has_async_calls(cli)) {
3634                 /*
3635                  * Can't use sync call while an async call is in flight
3636                  */
3637                 status = NT_STATUS_INVALID_PARAMETER;
3638                 goto fail;
3639         }
3640
3641         ev = event_context_init(frame);
3642         if (ev == NULL) {
3643                 status = NT_STATUS_NO_MEMORY;
3644                 goto fail;
3645         }
3646
3647         req = cli_dskattr_send(frame, ev, cli);
3648         if (req == NULL) {
3649                 status = NT_STATUS_NO_MEMORY;
3650                 goto fail;
3651         }
3652
3653         if (!tevent_req_poll(req, ev)) {
3654                 status = map_nt_error_from_unix(errno);
3655                 goto fail;
3656         }
3657
3658         status = cli_dskattr_recv(req, bsize, total, avail);
3659
3660  fail:
3661         TALLOC_FREE(frame);
3662         return status;
3663 }
3664
3665 /****************************************************************************
3666  Create and open a temporary file.
3667 ****************************************************************************/
3668
3669 static void cli_ctemp_done(struct tevent_req *subreq);
3670
3671 struct ctemp_state {
3672         uint16_t vwv[3];
3673         char *ret_path;
3674         uint16_t fnum;
3675 };
3676
3677 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
3678                                 struct event_context *ev,
3679                                 struct cli_state *cli,
3680                                 const char *path)
3681 {
3682         struct tevent_req *req = NULL, *subreq = NULL;
3683         struct ctemp_state *state = NULL;
3684         uint8_t additional_flags = 0;
3685         uint8_t *bytes = NULL;
3686
3687         req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
3688         if (req == NULL) {
3689                 return NULL;
3690         }
3691
3692         SSVAL(state->vwv,0,0);
3693         SIVALS(state->vwv+1,0,-1);
3694
3695         bytes = talloc_array(state, uint8_t, 1);
3696         if (tevent_req_nomem(bytes, req)) {
3697                 return tevent_req_post(req, ev);
3698         }
3699         bytes[0] = 4;
3700         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), path,
3701                                    strlen(path)+1, NULL);
3702         if (tevent_req_nomem(bytes, req)) {
3703                 return tevent_req_post(req, ev);
3704         }
3705
3706         subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
3707                               3, state->vwv, talloc_get_size(bytes), bytes);
3708         if (tevent_req_nomem(subreq, req)) {
3709                 return tevent_req_post(req, ev);
3710         }
3711         tevent_req_set_callback(subreq, cli_ctemp_done, req);
3712         return req;
3713 }
3714
3715 static void cli_ctemp_done(struct tevent_req *subreq)
3716 {
3717         struct tevent_req *req = tevent_req_callback_data(
3718                                 subreq, struct tevent_req);
3719         struct ctemp_state *state = tevent_req_data(
3720                                 req, struct ctemp_state);
3721         NTSTATUS status;
3722         uint8_t wcnt;
3723         uint16_t *vwv;
3724         uint32_t num_bytes = 0;
3725         uint8_t *bytes = NULL;
3726         uint8_t *inbuf;
3727
3728         status = cli_smb_recv(subreq, state, &inbuf, 1, &wcnt, &vwv,
3729                               &num_bytes, &bytes);
3730         TALLOC_FREE(subreq);
3731         if (tevent_req_nterror(req, status)) {
3732                 return;
3733         }
3734
3735         state->fnum = SVAL(vwv+0, 0);
3736
3737         /* From W2K3, the result is just the ASCII name */
3738         if (num_bytes < 2) {
3739                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
3740                 return;
3741         }
3742
3743         if (pull_string_talloc(state,
3744                         NULL,
3745                         0,
3746                         &state->ret_path,
3747                         bytes,
3748                         num_bytes,
3749                         STR_ASCII) == 0) {
3750                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
3751                 return;
3752         }
3753         tevent_req_done(req);
3754 }
3755
3756 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
3757                         TALLOC_CTX *ctx,
3758                         uint16_t *pfnum,
3759                         char **outfile)
3760 {
3761         struct ctemp_state *state = tevent_req_data(req,
3762                         struct ctemp_state);
3763         NTSTATUS status;
3764
3765         if (tevent_req_is_nterror(req, &status)) {
3766                 return status;
3767         }
3768         *pfnum = state->fnum;
3769         *outfile = talloc_strdup(ctx, state->ret_path);
3770         if (!*outfile) {
3771                 return NT_STATUS_NO_MEMORY;
3772         }
3773         return NT_STATUS_OK;
3774 }
3775
3776 NTSTATUS cli_ctemp(struct cli_state *cli,
3777                         TALLOC_CTX *ctx,
3778                         const char *path,
3779                         uint16_t *pfnum,
3780                         char **out_path)
3781 {
3782         TALLOC_CTX *frame = talloc_stackframe();
3783         struct event_context *ev;
3784         struct tevent_req *req;
3785         NTSTATUS status = NT_STATUS_OK;
3786
3787         if (cli_has_async_calls(cli)) {
3788                 /*
3789                  * Can't use sync call while an async call is in flight
3790                  */
3791                 status = NT_STATUS_INVALID_PARAMETER;
3792                 goto fail;
3793         }
3794
3795         ev = event_context_init(frame);
3796         if (ev == NULL) {
3797                 status = NT_STATUS_NO_MEMORY;
3798                 goto fail;
3799         }
3800
3801         req = cli_ctemp_send(frame, ev, cli, path);
3802         if (req == NULL) {
3803                 status = NT_STATUS_NO_MEMORY;
3804                 goto fail;
3805         }
3806
3807         if (!tevent_req_poll(req, ev)) {
3808                 status = map_nt_error_from_unix(errno);
3809                 goto fail;
3810         }
3811
3812         status = cli_ctemp_recv(req, ctx, pfnum, out_path);
3813
3814  fail:
3815         TALLOC_FREE(frame);
3816         return status;
3817 }
3818
3819 /*
3820    send a raw ioctl - used by the torture code
3821 */
3822 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
3823 {
3824         uint16_t vwv[3];
3825         NTSTATUS status;
3826
3827         SSVAL(vwv+0, 0, fnum);
3828         SSVAL(vwv+1, 0, code>>16);
3829         SSVAL(vwv+2, 0, (code&0xFFFF));
3830
3831         status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
3832                          NULL, 0, NULL, NULL, NULL, NULL);
3833         if (!NT_STATUS_IS_OK(status)) {
3834                 return status;
3835         }
3836         *blob = data_blob_null;
3837         return NT_STATUS_OK;
3838 }
3839
3840 /*********************************************************
3841  Set an extended attribute utility fn.
3842 *********************************************************/
3843
3844 static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
3845                            uint8_t *param, unsigned int param_len,
3846                            const char *ea_name,
3847                            const char *ea_val, size_t ea_len)
3848 {
3849         uint16_t setup[1];
3850         unsigned int data_len = 0;
3851         uint8_t *data = NULL;
3852         char *p;
3853         size_t ea_namelen = strlen(ea_name);
3854         NTSTATUS status;
3855
3856         SSVAL(setup, 0, setup_val);
3857
3858         if (ea_namelen == 0 && ea_len == 0) {
3859                 data_len = 4;
3860                 data = (uint8_t *)SMB_MALLOC(data_len);
3861                 if (!data) {
3862                         return NT_STATUS_NO_MEMORY;
3863                 }
3864                 p = (char *)data;
3865                 SIVAL(p,0,data_len);
3866         } else {
3867                 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
3868                 data = (uint8_t *)SMB_MALLOC(data_len);
3869                 if (!data) {
3870                         return NT_STATUS_NO_MEMORY;
3871                 }
3872                 p = (char *)data;
3873                 SIVAL(p,0,data_len);
3874                 p += 4;
3875                 SCVAL(p, 0, 0); /* EA flags. */
3876                 SCVAL(p, 1, ea_namelen);
3877                 SSVAL(p, 2, ea_len);
3878                 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
3879                 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
3880         }
3881
3882         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
3883                            setup, 1, 0,
3884                            param, param_len, 2,
3885                            data,  data_len, cli->max_xmit,
3886                            NULL,
3887                            NULL, 0, NULL, /* rsetup */
3888                            NULL, 0, NULL, /* rparam */
3889                            NULL, 0, NULL); /* rdata */
3890         SAFE_FREE(data);
3891         return status;
3892 }
3893
3894 /*********************************************************
3895  Set an extended attribute on a pathname.
3896 *********************************************************/
3897
3898 NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
3899                          const char *ea_name, const char *ea_val,
3900                          size_t ea_len)
3901 {
3902         unsigned int param_len = 0;
3903         uint8_t *param;
3904         size_t srclen = 2*(strlen(path)+1);
3905         char *p;
3906         NTSTATUS status;
3907
3908         param = SMB_MALLOC_ARRAY(uint8_t, 6+srclen+2);
3909         if (!param) {
3910                 return NT_STATUS_NO_MEMORY;
3911         }
3912         memset(param, '\0', 6);
3913         SSVAL(param,0,SMB_INFO_SET_EA);
3914         p = (char *)(&param[6]);
3915
3916         p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
3917         param_len = PTR_DIFF(p, param);
3918
3919         status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
3920                             ea_name, ea_val, ea_len);
3921         SAFE_FREE(param);
3922         return status;
3923 }
3924
3925 /*********************************************************
3926  Set an extended attribute on an fnum.
3927 *********************************************************/
3928
3929 NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
3930                          const char *ea_name, const char *ea_val,
3931                          size_t ea_len)
3932 {
3933         uint8_t param[6];
3934
3935         memset(param, 0, 6);
3936         SSVAL(param,0,fnum);
3937         SSVAL(param,2,SMB_INFO_SET_EA);
3938
3939         return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
3940                           ea_name, ea_val, ea_len);
3941 }
3942
3943 /*********************************************************
3944  Get an extended attribute list utility fn.
3945 *********************************************************/
3946
3947 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
3948                           size_t rdata_len,
3949                           size_t *pnum_eas, struct ea_struct **pea_list)
3950 {
3951         struct ea_struct *ea_list = NULL;
3952         size_t num_eas;
3953         size_t ea_size;
3954         const uint8_t *p;
3955
3956         if (rdata_len < 4) {
3957                 return false;
3958         }
3959
3960         ea_size = (size_t)IVAL(rdata,0);
3961         if (ea_size > rdata_len) {
3962                 return false;
3963         }
3964
3965         if (ea_size == 0) {
3966                 /* No EA's present. */
3967                 *pnum_eas = 0;
3968                 *pea_list = NULL;
3969                 return true;
3970         }
3971
3972         p = rdata + 4;
3973         ea_size -= 4;
3974
3975         /* Validate the EA list and count it. */
3976         for (num_eas = 0; ea_size >= 4; num_eas++) {
3977                 unsigned int ea_namelen = CVAL(p,1);
3978                 unsigned int ea_valuelen = SVAL(p,2);
3979                 if (ea_namelen == 0) {
3980                         return false;
3981                 }
3982                 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
3983                         return false;
3984                 }
3985                 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
3986                 p += 4 + ea_namelen + 1 + ea_valuelen;
3987         }
3988
3989         if (num_eas == 0) {
3990                 *pnum_eas = 0;
3991                 *pea_list = NULL;
3992                 return true;
3993         }
3994
3995         *pnum_eas = num_eas;
3996         if (!pea_list) {
3997                 /* Caller only wants number of EA's. */
3998                 return true;
3999         }
4000
4001         ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
4002         if (!ea_list) {
4003                 return false;
4004         }
4005
4006         ea_size = (size_t)IVAL(rdata,0);
4007         p = rdata + 4;
4008
4009         for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4010                 struct ea_struct *ea = &ea_list[num_eas];
4011                 fstring unix_ea_name;
4012                 unsigned int ea_namelen = CVAL(p,1);
4013                 unsigned int ea_valuelen = SVAL(p,2);
4014
4015                 ea->flags = CVAL(p,0);
4016                 unix_ea_name[0] = '\0';
4017                 pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
4018                 ea->name = talloc_strdup(ea_list, unix_ea_name);
4019                 if (!ea->name) {
4020                         goto fail;
4021                 }
4022                 /* Ensure the value is null terminated (in case it's a string). */
4023                 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4024                 if (!ea->value.data) {
4025                         goto fail;
4026                 }
4027                 if (ea_valuelen) {
4028                         memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4029                 }
4030                 ea->value.data[ea_valuelen] = 0;
4031                 ea->value.length--;
4032                 p += 4 + ea_namelen + 1 + ea_valuelen;
4033         }
4034
4035         *pea_list = ea_list;
4036         return true;
4037
4038 fail:
4039         TALLOC_FREE(ea_list);
4040         return false;
4041 }
4042
4043 /*********************************************************
4044  Get an extended attribute list from a pathname.
4045 *********************************************************/
4046
4047 struct cli_get_ea_list_path_state {
4048         uint32_t num_data;
4049         uint8_t *data;
4050 };
4051
4052 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4053
4054 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4055                                              struct tevent_context *ev,
4056                                              struct cli_state *cli,
4057                                              const char *fname)
4058 {
4059         struct tevent_req *req, *subreq;
4060         struct cli_get_ea_list_path_state *state;
4061
4062         req = tevent_req_create(mem_ctx, &state,
4063                                 struct cli_get_ea_list_path_state);
4064         if (req == NULL) {
4065                 return NULL;
4066         }
4067         subreq = cli_qpathinfo_send(state, ev, cli, fname,
4068                                     SMB_INFO_QUERY_ALL_EAS, 4,
4069                                     cli->max_xmit);
4070         if (tevent_req_nomem(subreq, req)) {
4071                 return tevent_req_post(req, ev);
4072         }
4073         tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4074         return req;
4075 }
4076
4077 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4078 {
4079         struct tevent_req *req = tevent_req_callback_data(
4080                                 subreq, struct tevent_req);
4081         struct cli_get_ea_list_path_state *state = tevent_req_data(
4082                 req, struct cli_get_ea_list_path_state);
4083         NTSTATUS status;
4084
4085         status = cli_qpathinfo_recv(subreq, state, &state->data,
4086                                     &state->num_data);
4087         TALLOC_FREE(subreq);
4088         if (tevent_req_nterror(req, status)) {
4089                 return;
4090         }
4091         tevent_req_done(req);
4092 }
4093
4094 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4095                                    size_t *pnum_eas, struct ea_struct **peas)
4096 {
4097         struct cli_get_ea_list_path_state *state = tevent_req_data(
4098                 req, struct cli_get_ea_list_path_state);
4099         NTSTATUS status;
4100
4101         if (tevent_req_is_nterror(req, &status)) {
4102                 return status;
4103         }
4104         if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4105                            pnum_eas, peas)) {
4106                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4107         }
4108         return NT_STATUS_OK;
4109 }
4110
4111 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
4112                 TALLOC_CTX *ctx,
4113                 size_t *pnum_eas,
4114                 struct ea_struct **pea_list)
4115 {
4116         TALLOC_CTX *frame = talloc_stackframe();
4117         struct event_context *ev = NULL;
4118         struct tevent_req *req = NULL;
4119         NTSTATUS status = NT_STATUS_NO_MEMORY;
4120
4121         if (cli_has_async_calls(cli)) {
4122                 /*
4123                  * Can't use sync call while an async call is in flight
4124                  */
4125                 status = NT_STATUS_INVALID_PARAMETER;
4126                 goto fail;
4127         }
4128         ev = event_context_init(frame);
4129         if (ev == NULL) {
4130                 goto fail;
4131         }
4132         req = cli_get_ea_list_path_send(frame, ev, cli, path);
4133         if (req == NULL) {
4134                 goto fail;
4135         }
4136         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4137                 goto fail;
4138         }
4139         status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
4140  fail:
4141         TALLOC_FREE(frame);
4142         return status;
4143 }
4144
4145 /****************************************************************************
4146  Convert open "flags" arg to uint32_t on wire.
4147 ****************************************************************************/
4148
4149 static uint32_t open_flags_to_wire(int flags)
4150 {
4151         int open_mode = flags & O_ACCMODE;
4152         uint32_t ret = 0;
4153
4154         switch (open_mode) {
4155                 case O_WRONLY:
4156                         ret |= SMB_O_WRONLY;
4157                         break;
4158                 case O_RDWR:
4159                         ret |= SMB_O_RDWR;
4160                         break;
4161                 default:
4162                 case O_RDONLY:
4163                         ret |= SMB_O_RDONLY;
4164                         break;
4165         }
4166
4167         if (flags & O_CREAT) {
4168                 ret |= SMB_O_CREAT;
4169         }
4170         if (flags & O_EXCL) {
4171                 ret |= SMB_O_EXCL;
4172         }
4173         if (flags & O_TRUNC) {
4174                 ret |= SMB_O_TRUNC;
4175         }
4176 #if defined(O_SYNC)
4177         if (flags & O_SYNC) {
4178                 ret |= SMB_O_SYNC;
4179         }
4180 #endif /* O_SYNC */
4181         if (flags & O_APPEND) {
4182                 ret |= SMB_O_APPEND;
4183         }
4184 #if defined(O_DIRECT)
4185         if (flags & O_DIRECT) {
4186                 ret |= SMB_O_DIRECT;
4187         }
4188 #endif
4189 #if defined(O_DIRECTORY)
4190         if (flags & O_DIRECTORY) {
4191                 ret |= SMB_O_DIRECTORY;
4192         }
4193 #endif
4194         return ret;
4195 }
4196
4197 /****************************************************************************
4198  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4199 ****************************************************************************/
4200
4201 struct posix_open_state {
4202         uint16_t setup;
4203         uint8_t *param;
4204         uint8_t data[18];
4205         uint16_t fnum; /* Out */
4206 };
4207
4208 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4209 {
4210         struct tevent_req *req = tevent_req_callback_data(
4211                                 subreq, struct tevent_req);
4212         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4213         NTSTATUS status;
4214         uint8_t *data;
4215         uint32_t num_data;
4216
4217         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
4218                                 NULL, 0, NULL, &data, 12, &num_data);
4219         TALLOC_FREE(subreq);
4220         if (tevent_req_nterror(req, status)) {
4221                 return;
4222         }
4223         state->fnum = SVAL(data,2);
4224         tevent_req_done(req);
4225 }
4226
4227 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4228                                         struct event_context *ev,
4229                                         struct cli_state *cli,
4230                                         const char *fname,
4231                                         int flags,
4232                                         mode_t mode,
4233                                         bool is_dir)
4234 {
4235         struct tevent_req *req = NULL, *subreq = NULL;
4236         struct posix_open_state *state = NULL;
4237         uint32_t wire_flags = open_flags_to_wire(flags);
4238
4239         req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4240         if (req == NULL) {
4241                 return NULL;
4242         }
4243
4244         /* Setup setup word. */
4245         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4246
4247         /* Setup param array. */
4248         state->param = talloc_array(state, uint8_t, 6);
4249         if (tevent_req_nomem(state->param, req)) {
4250                 return tevent_req_post(req, ev);
4251         }
4252         memset(state->param, '\0', 6);
4253         SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4254
4255         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
4256                                    strlen(fname)+1, NULL);
4257
4258         if (tevent_req_nomem(state->param, req)) {
4259                 return tevent_req_post(req, ev);
4260         }
4261
4262         /* Setup data words. */
4263         if (is_dir) {
4264                 wire_flags |= SMB_O_DIRECTORY;
4265         }
4266
4267         SIVAL(state->data,0,0); /* No oplock. */
4268         SIVAL(state->data,4,wire_flags);
4269         SIVAL(state->data,8,unix_perms_to_wire(mode));
4270         SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
4271         SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
4272
4273         subreq = cli_trans_send(state,                  /* mem ctx. */
4274                                 ev,                     /* event ctx. */
4275                                 cli,                    /* cli_state. */
4276                                 SMBtrans2,              /* cmd. */
4277                                 NULL,                   /* pipe name. */
4278                                 -1,                     /* fid. */
4279                                 0,                      /* function. */
4280                                 0,                      /* flags. */
4281                                 &state->setup,          /* setup. */
4282                                 1,                      /* num setup uint16_t words. */
4283                                 0,                      /* max returned setup. */
4284                                 state->param,           /* param. */
4285                                 talloc_get_size(state->param),/* num param. */
4286                                 2,                      /* max returned param. */
4287                                 state->data,            /* data. */
4288                                 18,                     /* num data. */
4289                                 12);                    /* max returned data. */
4290
4291         if (tevent_req_nomem(subreq, req)) {
4292                 return tevent_req_post(req, ev);
4293         }
4294         tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
4295         return req;
4296 }
4297
4298 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
4299                                         struct event_context *ev,
4300                                         struct cli_state *cli,
4301                                         const char *fname,
4302                                         int flags,
4303                                         mode_t mode)
4304 {
4305         return cli_posix_open_internal_send(mem_ctx, ev,
4306                                 cli, fname, flags, mode, false);
4307 }
4308
4309 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
4310 {
4311         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4312         NTSTATUS status;
4313
4314         if (tevent_req_is_nterror(req, &status)) {
4315                 return status;
4316         }
4317         *pfnum = state->fnum;
4318         return NT_STATUS_OK;
4319 }
4320
4321 /****************************************************************************
4322  Open - POSIX semantics. Doesn't request oplock.
4323 ****************************************************************************/
4324
4325 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
4326                         int flags, mode_t mode, uint16_t *pfnum)
4327 {
4328
4329         TALLOC_CTX *frame = talloc_stackframe();
4330         struct event_context *ev = NULL;
4331         struct tevent_req *req = NULL;
4332         NTSTATUS status = NT_STATUS_OK;
4333
4334         if (cli_has_async_calls(cli)) {
4335                 /*
4336                  * Can't use sync call while an async call is in flight
4337                  */
4338                 status = NT_STATUS_INVALID_PARAMETER;
4339                 goto fail;
4340         }
4341
4342         ev = event_context_init(frame);
4343         if (ev == NULL) {
4344                 status = NT_STATUS_NO_MEMORY;
4345                 goto fail;
4346         }
4347
4348         req = cli_posix_open_send(frame,
4349                                 ev,
4350                                 cli,
4351                                 fname,
4352                                 flags,
4353                                 mode);
4354         if (req == NULL) {
4355                 status = NT_STATUS_NO_MEMORY;
4356                 goto fail;
4357         }
4358
4359         if (!tevent_req_poll(req, ev)) {
4360                 status = map_nt_error_from_unix(errno);
4361                 goto fail;
4362         }
4363
4364         status = cli_posix_open_recv(req, pfnum);
4365
4366  fail:
4367         TALLOC_FREE(frame);
4368         return status;
4369 }
4370
4371 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
4372                                         struct event_context *ev,
4373                                         struct cli_state *cli,
4374                                         const char *fname,
4375                                         mode_t mode)
4376 {
4377         return cli_posix_open_internal_send(mem_ctx, ev,
4378                                 cli, fname, O_CREAT, mode, true);
4379 }
4380
4381 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
4382 {
4383         return tevent_req_simple_recv_ntstatus(req);
4384 }
4385
4386 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
4387 {
4388         TALLOC_CTX *frame = talloc_stackframe();
4389         struct event_context *ev = NULL;
4390         struct tevent_req *req = NULL;
4391         NTSTATUS status = NT_STATUS_OK;
4392
4393         if (cli_has_async_calls(cli)) {
4394                 /*
4395                  * Can't use sync call while an async call is in flight
4396                  */
4397                 status = NT_STATUS_INVALID_PARAMETER;
4398                 goto fail;
4399         }
4400
4401         ev = event_context_init(frame);
4402         if (ev == NULL) {
4403                 status = NT_STATUS_NO_MEMORY;
4404                 goto fail;
4405         }
4406
4407         req = cli_posix_mkdir_send(frame,
4408                                 ev,
4409                                 cli,
4410                                 fname,
4411                                 mode);
4412         if (req == NULL) {
4413                 status = NT_STATUS_NO_MEMORY;
4414                 goto fail;
4415         }
4416
4417         if (!tevent_req_poll(req, ev)) {
4418                 status = map_nt_error_from_unix(errno);
4419                 goto fail;
4420         }
4421
4422         status = cli_posix_mkdir_recv(req);
4423
4424  fail:
4425         TALLOC_FREE(frame);
4426         return status;
4427 }
4428
4429 /****************************************************************************
4430  unlink or rmdir - POSIX semantics.
4431 ****************************************************************************/
4432
4433 struct cli_posix_unlink_internal_state {
4434         uint8_t data[2];
4435 };
4436
4437 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
4438
4439 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
4440                                         struct event_context *ev,
4441                                         struct cli_state *cli,
4442                                         const char *fname,
4443                                         uint16_t level)
4444 {
4445         struct tevent_req *req = NULL, *subreq = NULL;
4446         struct cli_posix_unlink_internal_state *state = NULL;
4447
4448         req = tevent_req_create(mem_ctx, &state,
4449                                 struct cli_posix_unlink_internal_state);
4450         if (req == NULL) {
4451                 return NULL;
4452         }
4453
4454         /* Setup data word. */
4455         SSVAL(state->data, 0, level);
4456
4457         subreq = cli_setpathinfo_send(state, ev, cli,
4458                                       SMB_POSIX_PATH_UNLINK,
4459                                       fname,
4460                                       state->data, sizeof(state->data));
4461         if (tevent_req_nomem(subreq, req)) {
4462                 return tevent_req_post(req, ev);
4463         }
4464         tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
4465         return req;
4466 }
4467
4468 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
4469 {
4470         NTSTATUS status = cli_setpathinfo_recv(subreq);
4471         tevent_req_simple_finish_ntstatus(subreq, status);
4472 }
4473
4474 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
4475                                         struct event_context *ev,
4476                                         struct cli_state *cli,
4477                                         const char *fname)
4478 {
4479         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
4480                                               SMB_POSIX_UNLINK_FILE_TARGET);
4481 }
4482
4483 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
4484 {
4485         return tevent_req_simple_recv_ntstatus(req);
4486 }
4487
4488 /****************************************************************************
4489  unlink - POSIX semantics.
4490 ****************************************************************************/
4491
4492 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
4493 {
4494         TALLOC_CTX *frame = talloc_stackframe();
4495         struct event_context *ev = NULL;
4496         struct tevent_req *req = NULL;
4497         NTSTATUS status = NT_STATUS_OK;
4498
4499         if (cli_has_async_calls(cli)) {
4500                 /*
4501                  * Can't use sync call while an async call is in flight
4502                  */
4503                 status = NT_STATUS_INVALID_PARAMETER;
4504                 goto fail;
4505         }
4506
4507         ev = event_context_init(frame);
4508         if (ev == NULL) {
4509                 status = NT_STATUS_NO_MEMORY;
4510                 goto fail;
4511         }
4512
4513         req = cli_posix_unlink_send(frame,
4514                                 ev,
4515                                 cli,
4516                                 fname);
4517         if (req == NULL) {
4518                 status = NT_STATUS_NO_MEMORY;
4519                 goto fail;
4520         }
4521
4522         if (!tevent_req_poll(req, ev)) {
4523                 status = map_nt_error_from_unix(errno);
4524                 goto fail;
4525         }
4526
4527         status = cli_posix_unlink_recv(req);
4528
4529  fail:
4530         TALLOC_FREE(frame);
4531         return status;
4532 }
4533
4534 /****************************************************************************
4535  rmdir - POSIX semantics.
4536 ****************************************************************************/
4537
4538 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
4539                                         struct event_context *ev,
4540                                         struct cli_state *cli,
4541                                         const char *fname)
4542 {
4543         return cli_posix_unlink_internal_send(
4544                 mem_ctx, ev, cli, fname,
4545                 SMB_POSIX_UNLINK_DIRECTORY_TARGET);
4546 }
4547
4548 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
4549 {
4550         return tevent_req_simple_recv_ntstatus(req);
4551 }
4552
4553 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
4554 {
4555         TALLOC_CTX *frame = talloc_stackframe();
4556         struct event_context *ev = NULL;
4557         struct tevent_req *req = NULL;
4558         NTSTATUS status = NT_STATUS_OK;
4559
4560         if (cli_has_async_calls(cli)) {
4561                 /*
4562                  * Can't use sync call while an async call is in flight
4563                  */
4564                 status = NT_STATUS_INVALID_PARAMETER;
4565                 goto fail;
4566         }
4567
4568         ev = event_context_init(frame);
4569         if (ev == NULL) {
4570                 status = NT_STATUS_NO_MEMORY;
4571                 goto fail;
4572         }
4573
4574         req = cli_posix_rmdir_send(frame,
4575                                 ev,
4576                                 cli,
4577                                 fname);
4578         if (req == NULL) {
4579                 status = NT_STATUS_NO_MEMORY;
4580                 goto fail;
4581         }
4582
4583         if (!tevent_req_poll(req, ev)) {
4584                 status = map_nt_error_from_unix(errno);
4585                 goto fail;
4586         }
4587
4588         status = cli_posix_rmdir_recv(req, frame);
4589
4590  fail:
4591         TALLOC_FREE(frame);
4592         return status;
4593 }
4594
4595 /****************************************************************************
4596  filechangenotify
4597 ****************************************************************************/
4598
4599 struct cli_notify_state {
4600         uint8_t setup[8];
4601         uint32_t num_changes;
4602         struct notify_change *changes;
4603 };
4604
4605 static void cli_notify_done(struct tevent_req *subreq);
4606
4607 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
4608                                    struct tevent_context *ev,
4609                                    struct cli_state *cli, uint16_t fnum,
4610                                    uint32_t buffer_size,
4611                                    uint32_t completion_filter, bool recursive)
4612 {
4613         struct tevent_req *req, *subreq;
4614         struct cli_notify_state *state;
4615
4616         req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
4617         if (req == NULL) {
4618                 return NULL;
4619         }
4620
4621         SIVAL(state->setup, 0, completion_filter);
4622         SSVAL(state->setup, 4, fnum);
4623         SSVAL(state->setup, 6, recursive);
4624
4625         subreq = cli_trans_send(
4626                 state,                  /* mem ctx. */
4627                 ev,                     /* event ctx. */
4628                 cli,                    /* cli_state. */
4629                 SMBnttrans,             /* cmd. */
4630                 NULL,                   /* pipe name. */
4631                 -1,                     /* fid. */
4632                 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
4633                 0,                      /* flags. */
4634                 (uint16_t *)state->setup, /* setup. */
4635                 4,                      /* num setup uint16_t words. */
4636                 0,                      /* max returned setup. */
4637                 NULL,                   /* param. */
4638                 0,                      /* num param. */
4639                 buffer_size,            /* max returned param. */
4640                 NULL,                   /* data. */
4641                 0,                      /* num data. */
4642                 0);                     /* max returned data. */
4643
4644         if (tevent_req_nomem(subreq, req)) {
4645                 return tevent_req_post(req, ev);
4646         }
4647         tevent_req_set_callback(subreq, cli_notify_done, req);
4648         return req;
4649 }
4650
4651 static void cli_notify_done(struct tevent_req *subreq)
4652 {
4653         struct tevent_req *req = tevent_req_callback_data(
4654                 subreq, struct tevent_req);
4655         struct cli_notify_state *state = tevent_req_data(
4656                 req, struct cli_notify_state);
4657         NTSTATUS status;
4658         uint8_t *params;
4659         uint32_t i, ofs, num_params;
4660         uint16_t flags2;
4661
4662         status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
4663                                 &params, 0, &num_params, NULL, 0, NULL);
4664         TALLOC_FREE(subreq);
4665         if (tevent_req_nterror(req, status)) {
4666                 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
4667                 return;
4668         }
4669
4670         state->num_changes = 0;
4671         ofs = 0;
4672
4673         while (num_params - ofs > 12) {
4674                 uint32_t len = IVAL(params, ofs);
4675                 state->num_changes += 1;
4676
4677                 if ((len == 0) || (ofs+len >= num_params)) {
4678                         break;
4679                 }
4680                 ofs += len;
4681         }
4682
4683         state->changes = talloc_array(state, struct notify_change,
4684                                       state->num_changes);
4685         if (tevent_req_nomem(state->changes, req)) {
4686                 TALLOC_FREE(params);
4687                 return;
4688         }
4689
4690         ofs = 0;
4691
4692         for (i=0; i<state->num_changes; i++) {
4693                 uint32_t next = IVAL(params, ofs);
4694                 uint32_t len = IVAL(params, ofs+8);
4695                 ssize_t ret;
4696                 char *name;
4697
4698                 if ((next != 0) && (len+12 != next)) {
4699                         TALLOC_FREE(params);
4700                         tevent_req_nterror(
4701                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4702                         return;
4703                 }
4704
4705                 state->changes[i].action = IVAL(params, ofs+4);
4706                 ret = clistr_pull_talloc(params, (char *)params, flags2,
4707                                          &name, params+ofs+12, len,
4708                                          STR_TERMINATE|STR_UNICODE);
4709                 if (ret == -1) {
4710                         TALLOC_FREE(params);
4711                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4712                         return;
4713                 }
4714                 state->changes[i].name = name;
4715                 ofs += next;
4716         }
4717
4718         TALLOC_FREE(params);
4719         tevent_req_done(req);
4720 }
4721
4722 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4723                          uint32_t *pnum_changes,
4724                          struct notify_change **pchanges)
4725 {
4726         struct cli_notify_state *state = tevent_req_data(
4727                 req, struct cli_notify_state);
4728         NTSTATUS status;
4729
4730         if (tevent_req_is_nterror(req, &status)) {
4731                 return status;
4732         }
4733
4734         *pnum_changes = state->num_changes;
4735         *pchanges = talloc_move(mem_ctx, &state->changes);
4736         return NT_STATUS_OK;
4737 }
4738
4739 struct cli_qpathinfo_state {
4740         uint8_t *param;
4741         uint8_t *data;
4742         uint16_t setup[1];
4743         uint32_t min_rdata;
4744         uint8_t *rdata;
4745         uint32_t num_rdata;
4746 };
4747
4748 static void cli_qpathinfo_done(struct tevent_req *subreq);
4749
4750 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
4751                                       struct tevent_context *ev,
4752                                       struct cli_state *cli, const char *fname,
4753                                       uint16_t level, uint32_t min_rdata,
4754                                       uint32_t max_rdata)
4755 {
4756         struct tevent_req *req, *subreq;
4757         struct cli_qpathinfo_state *state;
4758
4759         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
4760         if (req == NULL) {
4761                 return NULL;
4762         }
4763         state->min_rdata = min_rdata;
4764         SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
4765
4766         state->param = talloc_zero_array(state, uint8_t, 6);
4767         if (tevent_req_nomem(state->param, req)) {
4768                 return tevent_req_post(req, ev);
4769         }
4770         SSVAL(state->param, 0, level);
4771         state->param = trans2_bytes_push_str(
4772                 state->param, cli_ucs2(cli), fname, strlen(fname)+1, NULL);
4773         if (tevent_req_nomem(state->param, req)) {
4774                 return tevent_req_post(req, ev);
4775         }
4776
4777         subreq = cli_trans_send(
4778                 state,                  /* mem ctx. */
4779                 ev,                     /* event ctx. */
4780                 cli,                    /* cli_state. */
4781                 SMBtrans2,              /* cmd. */
4782                 NULL,                   /* pipe name. */
4783                 -1,                     /* fid. */
4784                 0,                      /* function. */
4785                 0,                      /* flags. */
4786                 state->setup,           /* setup. */
4787                 1,                      /* num setup uint16_t words. */
4788                 0,                      /* max returned setup. */
4789                 state->param,           /* param. */
4790                 talloc_get_size(state->param),  /* num param. */
4791                 2,                      /* max returned param. */
4792                 NULL,                   /* data. */
4793                 0,                      /* num data. */
4794                 max_rdata);             /* max returned data. */
4795
4796         if (tevent_req_nomem(subreq, req)) {
4797                 return tevent_req_post(req, ev);
4798         }
4799         tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
4800         return req;
4801 }
4802
4803 static void cli_qpathinfo_done(struct tevent_req *subreq)
4804 {
4805         struct tevent_req *req = tevent_req_callback_data(
4806                 subreq, struct tevent_req);
4807         struct cli_qpathinfo_state *state = tevent_req_data(
4808                 req, struct cli_qpathinfo_state);
4809         NTSTATUS status;
4810
4811         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
4812                                 NULL, 0, NULL,
4813                                 &state->rdata, state->min_rdata,
4814                                 &state->num_rdata);
4815         if (tevent_req_nterror(req, status)) {
4816                 return;
4817         }
4818         tevent_req_done(req);
4819 }
4820
4821 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4822                             uint8_t **rdata, uint32_t *num_rdata)
4823 {
4824         struct cli_qpathinfo_state *state = tevent_req_data(
4825                 req, struct cli_qpathinfo_state);
4826         NTSTATUS status;
4827
4828         if (tevent_req_is_nterror(req, &status)) {
4829                 return status;
4830         }
4831         if (rdata != NULL) {
4832                 *rdata = talloc_move(mem_ctx, &state->rdata);
4833         } else {
4834                 TALLOC_FREE(state->rdata);
4835         }
4836         if (num_rdata != NULL) {
4837                 *num_rdata = state->num_rdata;
4838         }
4839         return NT_STATUS_OK;
4840 }
4841
4842 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
4843                        const char *fname, uint16_t level, uint32_t min_rdata,
4844                        uint32_t max_rdata,
4845                        uint8_t **rdata, uint32_t *num_rdata)
4846 {
4847         TALLOC_CTX *frame = talloc_stackframe();
4848         struct event_context *ev;
4849         struct tevent_req *req;
4850         NTSTATUS status = NT_STATUS_NO_MEMORY;
4851
4852         if (cli_has_async_calls(cli)) {
4853                 /*
4854                  * Can't use sync call while an async call is in flight
4855                  */
4856                 status = NT_STATUS_INVALID_PARAMETER;
4857                 goto fail;
4858         }
4859         ev = event_context_init(frame);
4860         if (ev == NULL) {
4861                 goto fail;
4862         }
4863         req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
4864                                  max_rdata);
4865         if (req == NULL) {
4866                 goto fail;
4867         }
4868         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4869                 goto fail;
4870         }
4871         status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
4872  fail:
4873         TALLOC_FREE(frame);
4874         return status;
4875 }
4876
4877 struct cli_qfileinfo_state {
4878         uint16_t setup[1];
4879         uint8_t param[4];
4880         uint8_t *data;
4881         uint32_t min_rdata;
4882         uint8_t *rdata;
4883         uint32_t num_rdata;
4884 };
4885
4886 static void cli_qfileinfo_done(struct tevent_req *subreq);
4887
4888 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
4889                                       struct tevent_context *ev,
4890                                       struct cli_state *cli, uint16_t fnum,
4891                                       uint16_t level, uint32_t min_rdata,
4892                                       uint32_t max_rdata)
4893 {
4894         struct tevent_req *req, *subreq;
4895         struct cli_qfileinfo_state *state;
4896
4897         req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
4898         if (req == NULL) {
4899                 return NULL;
4900         }
4901         state->min_rdata = min_rdata;
4902         SSVAL(state->param, 0, fnum);
4903         SSVAL(state->param, 2, level);
4904         SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
4905
4906         subreq = cli_trans_send(
4907                 state,                  /* mem ctx. */
4908                 ev,                     /* event ctx. */
4909                 cli,                    /* cli_state. */
4910                 SMBtrans2,              /* cmd. */
4911                 NULL,                   /* pipe name. */
4912                 -1,                     /* fid. */
4913                 0,                      /* function. */
4914                 0,                      /* flags. */
4915                 state->setup,           /* setup. */
4916                 1,                      /* num setup uint16_t words. */
4917                 0,                      /* max returned setup. */
4918                 state->param,           /* param. */
4919                 sizeof(state->param),   /* num param. */
4920                 2,                      /* max returned param. */
4921                 NULL,                   /* data. */
4922                 0,                      /* num data. */
4923                 max_rdata);             /* max returned data. */
4924
4925         if (tevent_req_nomem(subreq, req)) {
4926                 return tevent_req_post(req, ev);
4927         }
4928         tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
4929         return req;
4930 }
4931
4932 static void cli_qfileinfo_done(struct tevent_req *subreq)
4933 {
4934         struct tevent_req *req = tevent_req_callback_data(
4935                 subreq, struct tevent_req);
4936         struct cli_qfileinfo_state *state = tevent_req_data(
4937                 req, struct cli_qfileinfo_state);
4938         NTSTATUS status;
4939
4940         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
4941                                 NULL, 0, NULL,
4942                                 &state->rdata, state->min_rdata,
4943                                 &state->num_rdata);
4944         if (tevent_req_nterror(req, status)) {
4945                 return;
4946         }
4947         tevent_req_done(req);
4948 }
4949
4950 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4951                             uint8_t **rdata, uint32_t *num_rdata)
4952 {
4953         struct cli_qfileinfo_state *state = tevent_req_data(
4954                 req, struct cli_qfileinfo_state);
4955         NTSTATUS status;
4956
4957         if (tevent_req_is_nterror(req, &status)) {
4958                 return status;
4959         }
4960         if (rdata != NULL) {
4961                 *rdata = talloc_move(mem_ctx, &state->rdata);
4962         } else {
4963                 TALLOC_FREE(state->rdata);
4964         }
4965         if (num_rdata != NULL) {
4966                 *num_rdata = state->num_rdata;
4967         }
4968         return NT_STATUS_OK;
4969 }
4970
4971 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
4972                        uint16_t fnum, uint16_t level, uint32_t min_rdata,
4973                        uint32_t max_rdata,
4974                        uint8_t **rdata, uint32_t *num_rdata)
4975 {
4976         TALLOC_CTX *frame = talloc_stackframe();
4977         struct event_context *ev;
4978         struct tevent_req *req;
4979         NTSTATUS status = NT_STATUS_NO_MEMORY;
4980
4981         if (cli_has_async_calls(cli)) {
4982                 /*
4983                  * Can't use sync call while an async call is in flight
4984                  */
4985                 status = NT_STATUS_INVALID_PARAMETER;
4986                 goto fail;
4987         }
4988         ev = event_context_init(frame);
4989         if (ev == NULL) {
4990                 goto fail;
4991         }
4992         req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
4993                                  max_rdata);
4994         if (req == NULL) {
4995                 goto fail;
4996         }
4997         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4998                 goto fail;
4999         }
5000         status = cli_qfileinfo_recv(req, mem_ctx, rdata, num_rdata);
5001  fail:
5002         TALLOC_FREE(frame);
5003         return status;
5004 }
5005
5006 struct cli_flush_state {
5007         uint16_t vwv[1];
5008 };
5009
5010 static void cli_flush_done(struct tevent_req *subreq);
5011
5012 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
5013                                   struct event_context *ev,
5014                                   struct cli_state *cli,
5015                                   uint16_t fnum)
5016 {
5017         struct tevent_req *req, *subreq;
5018         struct cli_flush_state *state;
5019
5020         req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
5021         if (req == NULL) {
5022                 return NULL;
5023         }
5024         SSVAL(state->vwv + 0, 0, fnum);
5025
5026         subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 1, state->vwv,
5027                               0, NULL);
5028         if (tevent_req_nomem(subreq, req)) {
5029                 return tevent_req_post(req, ev);
5030         }
5031         tevent_req_set_callback(subreq, cli_flush_done, req);
5032         return req;
5033 }
5034
5035 static void cli_flush_done(struct tevent_req *subreq)
5036 {
5037         struct tevent_req *req = tevent_req_callback_data(
5038                 subreq, struct tevent_req);
5039         NTSTATUS status;
5040
5041         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5042         TALLOC_FREE(subreq);
5043         if (tevent_req_nterror(req, status)) {
5044                 return;
5045         }
5046         tevent_req_done(req);
5047 }
5048
5049 NTSTATUS cli_flush_recv(struct tevent_req *req)
5050 {
5051         return tevent_req_simple_recv_ntstatus(req);
5052 }
5053
5054 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
5055 {
5056         TALLOC_CTX *frame = talloc_stackframe();
5057         struct event_context *ev;
5058         struct tevent_req *req;
5059         NTSTATUS status = NT_STATUS_NO_MEMORY;
5060
5061         if (cli_has_async_calls(cli)) {
5062                 /*
5063                  * Can't use sync call while an async call is in flight
5064                  */
5065                 status = NT_STATUS_INVALID_PARAMETER;
5066                 goto fail;
5067         }
5068         ev = event_context_init(frame);
5069         if (ev == NULL) {
5070                 goto fail;
5071         }
5072         req = cli_flush_send(frame, ev, cli, fnum);
5073         if (req == NULL) {
5074                 goto fail;
5075         }
5076         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5077                 goto fail;
5078         }
5079         status = cli_flush_recv(req);
5080  fail:
5081         TALLOC_FREE(frame);
5082         return status;
5083 }
5084
5085 struct cli_shadow_copy_data_state {
5086         uint16_t setup[4];
5087         uint8_t *data;
5088         uint32_t num_data;
5089         bool get_names;
5090 };
5091
5092 static void cli_shadow_copy_data_done(struct tevent_req *subreq);
5093
5094 struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
5095                                              struct tevent_context *ev,
5096                                              struct cli_state *cli,
5097                                              uint16_t fnum,
5098                                              bool get_names)
5099 {
5100         struct tevent_req *req, *subreq;
5101         struct cli_shadow_copy_data_state *state;
5102         uint32_t ret_size;
5103
5104         req = tevent_req_create(mem_ctx, &state,
5105                                 struct cli_shadow_copy_data_state);
5106         if (req == NULL) {
5107                 return NULL;
5108         }
5109         state->get_names = get_names;
5110         ret_size = get_names ? cli->max_xmit : 16;
5111
5112         SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
5113         SSVAL(state->setup + 2, 0, fnum);
5114         SCVAL(state->setup + 3, 0, 0); /* isFsctl */
5115         SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
5116
5117         subreq = cli_trans_send(
5118                 state, ev, cli, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
5119                 state->setup, ARRAY_SIZE(state->setup), 0,
5120                 NULL, 0, 0,
5121                 NULL, 0, ret_size);
5122         if (tevent_req_nomem(subreq, req)) {
5123                 return tevent_req_post(req, ev);
5124         }
5125         tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
5126         return req;
5127 }
5128
5129 static void cli_shadow_copy_data_done(struct tevent_req *subreq)
5130 {
5131         struct tevent_req *req = tevent_req_callback_data(
5132                 subreq, struct tevent_req);
5133         struct cli_shadow_copy_data_state *state = tevent_req_data(
5134                 req, struct cli_shadow_copy_data_state);
5135         NTSTATUS status;
5136
5137         status = cli_trans_recv(subreq, state, NULL,
5138                                 NULL, 0, NULL, /* setup */
5139                                 NULL, 0, NULL, /* param */
5140                                 &state->data, 12, &state->num_data);
5141         TALLOC_FREE(subreq);
5142         if (tevent_req_nterror(req, status)) {
5143                 return;
5144         }
5145         tevent_req_done(req);
5146 }
5147
5148 NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5149                                    char ***pnames, int *pnum_names)
5150 {
5151         struct cli_shadow_copy_data_state *state = tevent_req_data(
5152                 req, struct cli_shadow_copy_data_state);
5153         char **names;
5154         int i, num_names;
5155         uint32_t dlength;
5156         NTSTATUS status;
5157
5158         if (tevent_req_is_nterror(req, &status)) {
5159                 return status;
5160         }
5161         num_names = IVAL(state->data, 4);
5162         dlength = IVAL(state->data, 8);
5163
5164         if (!state->get_names) {
5165                 *pnum_names = num_names;
5166                 return NT_STATUS_OK;
5167         }
5168
5169         if (dlength+12 > state->num_data) {
5170                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
5171         }
5172         names = talloc_array(mem_ctx, char *, num_names);
5173         if (names == NULL) {
5174                 return NT_STATUS_NO_MEMORY;
5175         }
5176
5177         for (i=0; i<num_names; i++) {
5178                 bool ret;
5179                 uint8_t *src;
5180                 size_t converted_size;
5181
5182                 src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
5183                 ret = convert_string_talloc(
5184                         names, CH_UTF16LE, CH_UNIX,
5185                         src, 2 * sizeof(SHADOW_COPY_LABEL),
5186                         &names[i], &converted_size);
5187                 if (!ret) {
5188                         TALLOC_FREE(names);
5189                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
5190                 }
5191         }
5192         *pnum_names = num_names;
5193         *pnames = names;
5194         return NT_STATUS_OK;
5195 }
5196
5197 NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5198                               uint16_t fnum, bool get_names,
5199                               char ***pnames, int *pnum_names)
5200 {
5201         TALLOC_CTX *frame = talloc_stackframe();
5202         struct event_context *ev;
5203         struct tevent_req *req;
5204         NTSTATUS status = NT_STATUS_NO_MEMORY;
5205
5206         if (cli_has_async_calls(cli)) {
5207                 /*
5208                  * Can't use sync call while an async call is in flight
5209                  */
5210                 status = NT_STATUS_INVALID_PARAMETER;
5211                 goto fail;
5212         }
5213         ev = event_context_init(frame);
5214         if (ev == NULL) {
5215                 goto fail;
5216         }
5217         req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
5218         if (req == NULL) {
5219                 goto fail;
5220         }
5221         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5222                 goto fail;
5223         }
5224         status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
5225  fail:
5226         TALLOC_FREE(frame);
5227         return status;
5228 }