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