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