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