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