s3: Convert cli_set_ea() to cli_trans()
[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 NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
4070                            uint8_t *param, unsigned int param_len,
4071                            const char *ea_name,
4072                            const char *ea_val, size_t ea_len)
4073 {
4074         uint16_t setup[0];
4075         unsigned int data_len = 0;
4076         uint8_t *data = NULL;
4077         char *p;
4078         size_t ea_namelen = strlen(ea_name);
4079         NTSTATUS status;
4080
4081         SSVAL(setup, 0, setup_val);
4082
4083         if (ea_namelen == 0 && ea_len == 0) {
4084                 data_len = 4;
4085                 data = (uint8_t *)SMB_MALLOC(data_len);
4086                 if (!data) {
4087                         return NT_STATUS_NO_MEMORY;
4088                 }
4089                 p = (char *)data;
4090                 SIVAL(p,0,data_len);
4091         } else {
4092                 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4093                 data = (uint8_t *)SMB_MALLOC(data_len);
4094                 if (!data) {
4095                         return NT_STATUS_NO_MEMORY;
4096                 }
4097                 p = (char *)data;
4098                 SIVAL(p,0,data_len);
4099                 p += 4;
4100                 SCVAL(p, 0, 0); /* EA flags. */
4101                 SCVAL(p, 1, ea_namelen);
4102                 SSVAL(p, 2, ea_len);
4103                 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4104                 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4105         }
4106
4107         status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
4108                            setup, 1, 0,
4109                            param, param_len, 2,
4110                            data,  data_len, cli->max_xmit,
4111                            NULL,
4112                            NULL, 0, NULL, /* rsetup */
4113                            NULL, 0, NULL, /* rparam */
4114                            NULL, 0, NULL); /* rdata */
4115         SAFE_FREE(data);
4116         return status;
4117 }
4118
4119 /*********************************************************
4120  Set an extended attribute on a pathname.
4121 *********************************************************/
4122
4123 bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len)
4124 {
4125         uint16_t setup = TRANSACT2_SETPATHINFO;
4126         unsigned int param_len = 0;
4127         uint8_t *param;
4128         size_t srclen = 2*(strlen(path)+1);
4129         char *p;
4130         NTSTATUS status;
4131
4132         param = SMB_MALLOC_ARRAY(uint8_t, 6+srclen+2);
4133         if (!param) {
4134                 return false;
4135         }
4136         memset(param, '\0', 6);
4137         SSVAL(param,0,SMB_INFO_SET_EA);
4138         p = (char *)(&param[6]);
4139
4140         p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
4141         param_len = PTR_DIFF(p, param);
4142
4143         status = cli_set_ea(cli, setup, param, param_len, ea_name,
4144                             ea_val, ea_len);
4145         SAFE_FREE(param);
4146         return NT_STATUS_IS_OK(status);
4147 }
4148
4149 /*********************************************************
4150  Set an extended attribute on an fnum.
4151 *********************************************************/
4152
4153 bool cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum, const char *ea_name, const char *ea_val, size_t ea_len)
4154 {
4155         uint8_t param[6];
4156         uint16_t setup = TRANSACT2_SETFILEINFO;
4157         NTSTATUS status;
4158
4159         memset(param, 0, 6);
4160         SSVAL(param,0,fnum);
4161         SSVAL(param,2,SMB_INFO_SET_EA);
4162
4163         status = cli_set_ea(cli, setup, param, 6, ea_name, ea_val, ea_len);
4164         return NT_STATUS_IS_OK(status);
4165 }
4166
4167 /*********************************************************
4168  Get an extended attribute list utility fn.
4169 *********************************************************/
4170
4171 static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
4172                           size_t rdata_len,
4173                           size_t *pnum_eas, struct ea_struct **pea_list)
4174 {
4175         struct ea_struct *ea_list = NULL;
4176         size_t num_eas;
4177         size_t ea_size;
4178         const uint8_t *p;
4179
4180         if (rdata_len < 4) {
4181                 return false;
4182         }
4183
4184         ea_size = (size_t)IVAL(rdata,0);
4185         if (ea_size > rdata_len) {
4186                 return false;
4187         }
4188
4189         if (ea_size == 0) {
4190                 /* No EA's present. */
4191                 *pnum_eas = 0;
4192                 *pea_list = NULL;
4193                 return true;
4194         }
4195
4196         p = rdata + 4;
4197         ea_size -= 4;
4198
4199         /* Validate the EA list and count it. */
4200         for (num_eas = 0; ea_size >= 4; num_eas++) {
4201                 unsigned int ea_namelen = CVAL(p,1);
4202                 unsigned int ea_valuelen = SVAL(p,2);
4203                 if (ea_namelen == 0) {
4204                         return false;
4205                 }
4206                 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4207                         return false;
4208                 }
4209                 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4210                 p += 4 + ea_namelen + 1 + ea_valuelen;
4211         }
4212
4213         if (num_eas == 0) {
4214                 *pnum_eas = 0;
4215                 *pea_list = NULL;
4216                 return true;
4217         }
4218
4219         *pnum_eas = num_eas;
4220         if (!pea_list) {
4221                 /* Caller only wants number of EA's. */
4222                 return true;
4223         }
4224
4225         ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
4226         if (!ea_list) {
4227                 return false;
4228         }
4229
4230         ea_size = (size_t)IVAL(rdata,0);
4231         p = rdata + 4;
4232
4233         for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4234                 struct ea_struct *ea = &ea_list[num_eas];
4235                 fstring unix_ea_name;
4236                 unsigned int ea_namelen = CVAL(p,1);
4237                 unsigned int ea_valuelen = SVAL(p,2);
4238
4239                 ea->flags = CVAL(p,0);
4240                 unix_ea_name[0] = '\0';
4241                 pull_ascii_fstring(unix_ea_name, p + 4);
4242                 ea->name = talloc_strdup(ea_list, unix_ea_name);
4243                 if (!ea->name) {
4244                         goto fail;
4245                 }
4246                 /* Ensure the value is null terminated (in case it's a string). */
4247                 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4248                 if (!ea->value.data) {
4249                         goto fail;
4250                 }
4251                 if (ea_valuelen) {
4252                         memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4253                 }
4254                 ea->value.data[ea_valuelen] = 0;
4255                 ea->value.length--;
4256                 p += 4 + ea_namelen + 1 + ea_valuelen;
4257         }
4258
4259         *pea_list = ea_list;
4260         return true;
4261
4262 fail:
4263         TALLOC_FREE(ea_list);
4264         return false;
4265 }
4266
4267 /*********************************************************
4268  Get an extended attribute list from a pathname.
4269 *********************************************************/
4270
4271 struct cli_get_ea_list_path_state {
4272         uint32_t num_data;
4273         uint8_t *data;
4274 };
4275
4276 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4277
4278 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4279                                              struct tevent_context *ev,
4280                                              struct cli_state *cli,
4281                                              const char *fname)
4282 {
4283         struct tevent_req *req, *subreq;
4284         struct cli_get_ea_list_path_state *state;
4285
4286         req = tevent_req_create(mem_ctx, &state,
4287                                 struct cli_get_ea_list_path_state);
4288         if (req == NULL) {
4289                 return NULL;
4290         }
4291         subreq = cli_qpathinfo_send(state, ev, cli, fname,
4292                                     SMB_INFO_QUERY_ALL_EAS, 4,
4293                                     cli->max_xmit);
4294         if (tevent_req_nomem(subreq, req)) {
4295                 return tevent_req_post(req, ev);
4296         }
4297         tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4298         return req;
4299 }
4300
4301 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4302 {
4303         struct tevent_req *req = tevent_req_callback_data(
4304                                 subreq, struct tevent_req);
4305         struct cli_get_ea_list_path_state *state = tevent_req_data(
4306                 req, struct cli_get_ea_list_path_state);
4307         NTSTATUS status;
4308
4309         status = cli_qpathinfo_recv(subreq, state, &state->data,
4310                                     &state->num_data);
4311         TALLOC_FREE(subreq);
4312         if (!NT_STATUS_IS_OK(status)) {
4313                 tevent_req_nterror(req, status);
4314                 return;
4315         }
4316         tevent_req_done(req);
4317 }
4318
4319 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4320                                    size_t *pnum_eas, struct ea_struct **peas)
4321 {
4322         struct cli_get_ea_list_path_state *state = tevent_req_data(
4323                 req, struct cli_get_ea_list_path_state);
4324         NTSTATUS status;
4325
4326         if (tevent_req_is_nterror(req, &status)) {
4327                 return status;
4328         }
4329         if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4330                            pnum_eas, peas)) {
4331                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4332         }
4333         return NT_STATUS_OK;
4334 }
4335
4336 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
4337                 TALLOC_CTX *ctx,
4338                 size_t *pnum_eas,
4339                 struct ea_struct **pea_list)
4340 {
4341         TALLOC_CTX *frame = talloc_stackframe();
4342         struct event_context *ev = NULL;
4343         struct tevent_req *req = NULL;
4344         NTSTATUS status = NT_STATUS_NO_MEMORY;
4345
4346         if (cli_has_async_calls(cli)) {
4347                 /*
4348                  * Can't use sync call while an async call is in flight
4349                  */
4350                 status = NT_STATUS_INVALID_PARAMETER;
4351                 goto fail;
4352         }
4353         ev = event_context_init(frame);
4354         if (ev == NULL) {
4355                 goto fail;
4356         }
4357         req = cli_get_ea_list_path_send(frame, ev, cli, path);
4358         if (req == NULL) {
4359                 goto fail;
4360         }
4361         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4362                 goto fail;
4363         }
4364         status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
4365  fail:
4366         TALLOC_FREE(frame);
4367         if (!NT_STATUS_IS_OK(status)) {
4368                 cli_set_error(cli, status);
4369         }
4370         return status;
4371 }
4372
4373 /****************************************************************************
4374  Convert open "flags" arg to uint32_t on wire.
4375 ****************************************************************************/
4376
4377 static uint32_t open_flags_to_wire(int flags)
4378 {
4379         int open_mode = flags & O_ACCMODE;
4380         uint32_t ret = 0;
4381
4382         switch (open_mode) {
4383                 case O_WRONLY:
4384                         ret |= SMB_O_WRONLY;
4385                         break;
4386                 case O_RDWR:
4387                         ret |= SMB_O_RDWR;
4388                         break;
4389                 default:
4390                 case O_RDONLY:
4391                         ret |= SMB_O_RDONLY;
4392                         break;
4393         }
4394
4395         if (flags & O_CREAT) {
4396                 ret |= SMB_O_CREAT;
4397         }
4398         if (flags & O_EXCL) {
4399                 ret |= SMB_O_EXCL;
4400         }
4401         if (flags & O_TRUNC) {
4402                 ret |= SMB_O_TRUNC;
4403         }
4404 #if defined(O_SYNC)
4405         if (flags & O_SYNC) {
4406                 ret |= SMB_O_SYNC;
4407         }
4408 #endif /* O_SYNC */
4409         if (flags & O_APPEND) {
4410                 ret |= SMB_O_APPEND;
4411         }
4412 #if defined(O_DIRECT)
4413         if (flags & O_DIRECT) {
4414                 ret |= SMB_O_DIRECT;
4415         }
4416 #endif
4417 #if defined(O_DIRECTORY)
4418         if (flags & O_DIRECTORY) {
4419                 ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4420                 ret |= SMB_O_DIRECTORY;
4421         }
4422 #endif
4423         return ret;
4424 }
4425
4426 /****************************************************************************
4427  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4428 ****************************************************************************/
4429
4430 struct posix_open_state {
4431         uint16_t setup;
4432         uint8_t *param;
4433         uint8_t data[18];
4434         uint16_t fnum; /* Out */
4435 };
4436
4437 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4438 {
4439         struct tevent_req *req = tevent_req_callback_data(
4440                                 subreq, struct tevent_req);
4441         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4442         NTSTATUS status;
4443         uint8_t *data;
4444         uint32_t num_data;
4445
4446         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
4447                                 NULL, 0, NULL, &data, 12, &num_data);
4448         TALLOC_FREE(subreq);
4449         if (!NT_STATUS_IS_OK(status)) {
4450                 tevent_req_nterror(req, status);
4451                 return;
4452         }
4453         state->fnum = SVAL(data,2);
4454         tevent_req_done(req);
4455 }
4456
4457 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4458                                         struct event_context *ev,
4459                                         struct cli_state *cli,
4460                                         const char *fname,
4461                                         int flags,
4462                                         mode_t mode,
4463                                         bool is_dir)
4464 {
4465         struct tevent_req *req = NULL, *subreq = NULL;
4466         struct posix_open_state *state = NULL;
4467         uint32_t wire_flags = open_flags_to_wire(flags);
4468
4469         req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4470         if (req == NULL) {
4471                 return NULL;
4472         }
4473
4474         /* Setup setup word. */
4475         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4476
4477         /* Setup param array. */
4478         state->param = talloc_array(state, uint8_t, 6);
4479         if (tevent_req_nomem(state->param, req)) {
4480                 return tevent_req_post(req, ev);
4481         }
4482         memset(state->param, '\0', 6);
4483         SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4484
4485         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
4486                                    strlen(fname)+1, NULL);
4487
4488         if (tevent_req_nomem(state->param, req)) {
4489                 return tevent_req_post(req, ev);
4490         }
4491
4492         /* Setup data words. */
4493         if (is_dir) {
4494                 wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4495                 wire_flags |= SMB_O_DIRECTORY;
4496         }
4497
4498         SIVAL(state->data,0,0); /* No oplock. */
4499         SIVAL(state->data,4,wire_flags);
4500         SIVAL(state->data,8,unix_perms_to_wire(mode));
4501         SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
4502         SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
4503
4504         subreq = cli_trans_send(state,                  /* mem ctx. */
4505                                 ev,                     /* event ctx. */
4506                                 cli,                    /* cli_state. */
4507                                 SMBtrans2,              /* cmd. */
4508                                 NULL,                   /* pipe name. */
4509                                 -1,                     /* fid. */
4510                                 0,                      /* function. */
4511                                 0,                      /* flags. */
4512                                 &state->setup,          /* setup. */
4513                                 1,                      /* num setup uint16_t words. */
4514                                 0,                      /* max returned setup. */
4515                                 state->param,           /* param. */
4516                                 talloc_get_size(state->param),/* num param. */
4517                                 2,                      /* max returned param. */
4518                                 state->data,            /* data. */
4519                                 18,                     /* num data. */
4520                                 12);                    /* max returned data. */
4521
4522         if (tevent_req_nomem(subreq, req)) {
4523                 return tevent_req_post(req, ev);
4524         }
4525         tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
4526         return req;
4527 }
4528
4529 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
4530                                         struct event_context *ev,
4531                                         struct cli_state *cli,
4532                                         const char *fname,
4533                                         int flags,
4534                                         mode_t mode)
4535 {
4536         return cli_posix_open_internal_send(mem_ctx, ev,
4537                                 cli, fname, flags, mode, false);
4538 }
4539
4540 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
4541 {
4542         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4543         NTSTATUS status;
4544
4545         if (tevent_req_is_nterror(req, &status)) {
4546                 return status;
4547         }
4548         *pfnum = state->fnum;
4549         return NT_STATUS_OK;
4550 }
4551
4552 /****************************************************************************
4553  Open - POSIX semantics. Doesn't request oplock.
4554 ****************************************************************************/
4555
4556 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
4557                         int flags, mode_t mode, uint16_t *pfnum)
4558 {
4559
4560         TALLOC_CTX *frame = talloc_stackframe();
4561         struct event_context *ev = NULL;
4562         struct tevent_req *req = NULL;
4563         NTSTATUS status = NT_STATUS_OK;
4564
4565         if (cli_has_async_calls(cli)) {
4566                 /*
4567                  * Can't use sync call while an async call is in flight
4568                  */
4569                 status = NT_STATUS_INVALID_PARAMETER;
4570                 goto fail;
4571         }
4572
4573         ev = event_context_init(frame);
4574         if (ev == NULL) {
4575                 status = NT_STATUS_NO_MEMORY;
4576                 goto fail;
4577         }
4578
4579         req = cli_posix_open_send(frame,
4580                                 ev,
4581                                 cli,
4582                                 fname,
4583                                 flags,
4584                                 mode);
4585         if (req == NULL) {
4586                 status = NT_STATUS_NO_MEMORY;
4587                 goto fail;
4588         }
4589
4590         if (!tevent_req_poll(req, ev)) {
4591                 status = map_nt_error_from_unix(errno);
4592                 goto fail;
4593         }
4594
4595         status = cli_posix_open_recv(req, pfnum);
4596
4597  fail:
4598         TALLOC_FREE(frame);
4599         if (!NT_STATUS_IS_OK(status)) {
4600                 cli_set_error(cli, status);
4601         }
4602         return status;
4603 }
4604
4605 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
4606                                         struct event_context *ev,
4607                                         struct cli_state *cli,
4608                                         const char *fname,
4609                                         mode_t mode)
4610 {
4611         return cli_posix_open_internal_send(mem_ctx, ev,
4612                                 cli, fname, O_CREAT, mode, true);
4613 }
4614
4615 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
4616 {
4617         return tevent_req_simple_recv_ntstatus(req);
4618 }
4619
4620 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
4621 {
4622         TALLOC_CTX *frame = talloc_stackframe();
4623         struct event_context *ev = NULL;
4624         struct tevent_req *req = NULL;
4625         NTSTATUS status = NT_STATUS_OK;
4626
4627         if (cli_has_async_calls(cli)) {
4628                 /*
4629                  * Can't use sync call while an async call is in flight
4630                  */
4631                 status = NT_STATUS_INVALID_PARAMETER;
4632                 goto fail;
4633         }
4634
4635         ev = event_context_init(frame);
4636         if (ev == NULL) {
4637                 status = NT_STATUS_NO_MEMORY;
4638                 goto fail;
4639         }
4640
4641         req = cli_posix_mkdir_send(frame,
4642                                 ev,
4643                                 cli,
4644                                 fname,
4645                                 mode);
4646         if (req == NULL) {
4647                 status = NT_STATUS_NO_MEMORY;
4648                 goto fail;
4649         }
4650
4651         if (!tevent_req_poll(req, ev)) {
4652                 status = map_nt_error_from_unix(errno);
4653                 goto fail;
4654         }
4655
4656         status = cli_posix_mkdir_recv(req);
4657
4658  fail:
4659         TALLOC_FREE(frame);
4660         if (!NT_STATUS_IS_OK(status)) {
4661                 cli_set_error(cli, status);
4662         }
4663         return status;
4664 }
4665
4666 /****************************************************************************
4667  unlink or rmdir - POSIX semantics.
4668 ****************************************************************************/
4669
4670 struct cli_posix_unlink_internal_state {
4671         uint8_t data[2];
4672 };
4673
4674 static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
4675
4676 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
4677                                         struct event_context *ev,
4678                                         struct cli_state *cli,
4679                                         const char *fname,
4680                                         uint16_t level)
4681 {
4682         struct tevent_req *req = NULL, *subreq = NULL;
4683         struct cli_posix_unlink_internal_state *state = NULL;
4684
4685         req = tevent_req_create(mem_ctx, &state,
4686                                 struct cli_posix_unlink_internal_state);
4687         if (req == NULL) {
4688                 return NULL;
4689         }
4690
4691         /* Setup data word. */
4692         SSVAL(state->data, 0, level);
4693
4694         subreq = cli_setpathinfo_send(state, ev, cli,
4695                                       SMB_POSIX_PATH_UNLINK,
4696                                       fname,
4697                                       state->data, sizeof(state->data));
4698         if (tevent_req_nomem(subreq, req)) {
4699                 return tevent_req_post(req, ev);
4700         }
4701         tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
4702         return req;
4703 }
4704
4705 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
4706 {
4707         NTSTATUS status = cli_setpathinfo_recv(subreq);
4708         tevent_req_simple_finish_ntstatus(subreq, status);
4709 }
4710
4711 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
4712                                         struct event_context *ev,
4713                                         struct cli_state *cli,
4714                                         const char *fname)
4715 {
4716         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname,
4717                                               SMB_POSIX_UNLINK_FILE_TARGET);
4718 }
4719
4720 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
4721 {
4722         return tevent_req_simple_recv_ntstatus(req);
4723 }
4724
4725 /****************************************************************************
4726  unlink - POSIX semantics.
4727 ****************************************************************************/
4728
4729 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
4730 {
4731         TALLOC_CTX *frame = talloc_stackframe();
4732         struct event_context *ev = NULL;
4733         struct tevent_req *req = NULL;
4734         NTSTATUS status = NT_STATUS_OK;
4735
4736         if (cli_has_async_calls(cli)) {
4737                 /*
4738                  * Can't use sync call while an async call is in flight
4739                  */
4740                 status = NT_STATUS_INVALID_PARAMETER;
4741                 goto fail;
4742         }
4743
4744         ev = event_context_init(frame);
4745         if (ev == NULL) {
4746                 status = NT_STATUS_NO_MEMORY;
4747                 goto fail;
4748         }
4749
4750         req = cli_posix_unlink_send(frame,
4751                                 ev,
4752                                 cli,
4753                                 fname);
4754         if (req == NULL) {
4755                 status = NT_STATUS_NO_MEMORY;
4756                 goto fail;
4757         }
4758
4759         if (!tevent_req_poll(req, ev)) {
4760                 status = map_nt_error_from_unix(errno);
4761                 goto fail;
4762         }
4763
4764         status = cli_posix_unlink_recv(req);
4765
4766  fail:
4767         TALLOC_FREE(frame);
4768         if (!NT_STATUS_IS_OK(status)) {
4769                 cli_set_error(cli, status);
4770         }
4771         return status;
4772 }
4773
4774 /****************************************************************************
4775  rmdir - POSIX semantics.
4776 ****************************************************************************/
4777
4778 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
4779                                         struct event_context *ev,
4780                                         struct cli_state *cli,
4781                                         const char *fname)
4782 {
4783         return cli_posix_unlink_internal_send(
4784                 mem_ctx, ev, cli, fname,
4785                 SMB_POSIX_UNLINK_DIRECTORY_TARGET);
4786 }
4787
4788 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
4789 {
4790         return tevent_req_simple_recv_ntstatus(req);
4791 }
4792
4793 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
4794 {
4795         TALLOC_CTX *frame = talloc_stackframe();
4796         struct event_context *ev = NULL;
4797         struct tevent_req *req = NULL;
4798         NTSTATUS status = NT_STATUS_OK;
4799
4800         if (cli_has_async_calls(cli)) {
4801                 /*
4802                  * Can't use sync call while an async call is in flight
4803                  */
4804                 status = NT_STATUS_INVALID_PARAMETER;
4805                 goto fail;
4806         }
4807
4808         ev = event_context_init(frame);
4809         if (ev == NULL) {
4810                 status = NT_STATUS_NO_MEMORY;
4811                 goto fail;
4812         }
4813
4814         req = cli_posix_rmdir_send(frame,
4815                                 ev,
4816                                 cli,
4817                                 fname);
4818         if (req == NULL) {
4819                 status = NT_STATUS_NO_MEMORY;
4820                 goto fail;
4821         }
4822
4823         if (!tevent_req_poll(req, ev)) {
4824                 status = map_nt_error_from_unix(errno);
4825                 goto fail;
4826         }
4827
4828         status = cli_posix_rmdir_recv(req, frame);
4829
4830  fail:
4831         TALLOC_FREE(frame);
4832         if (!NT_STATUS_IS_OK(status)) {
4833                 cli_set_error(cli, status);
4834         }
4835         return status;
4836 }
4837
4838 /****************************************************************************
4839  filechangenotify
4840 ****************************************************************************/
4841
4842 struct cli_notify_state {
4843         uint8_t setup[8];
4844         uint32_t num_changes;
4845         struct notify_change *changes;
4846 };
4847
4848 static void cli_notify_done(struct tevent_req *subreq);
4849
4850 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
4851                                    struct tevent_context *ev,
4852                                    struct cli_state *cli, uint16_t fnum,
4853                                    uint32_t buffer_size,
4854                                    uint32_t completion_filter, bool recursive)
4855 {
4856         struct tevent_req *req, *subreq;
4857         struct cli_notify_state *state;
4858
4859         req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
4860         if (req == NULL) {
4861                 return NULL;
4862         }
4863
4864         SIVAL(state->setup, 0, completion_filter);
4865         SSVAL(state->setup, 4, fnum);
4866         SSVAL(state->setup, 6, recursive);
4867
4868         subreq = cli_trans_send(
4869                 state,                  /* mem ctx. */
4870                 ev,                     /* event ctx. */
4871                 cli,                    /* cli_state. */
4872                 SMBnttrans,             /* cmd. */
4873                 NULL,                   /* pipe name. */
4874                 -1,                     /* fid. */
4875                 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
4876                 0,                      /* flags. */
4877                 (uint16_t *)state->setup, /* setup. */
4878                 4,                      /* num setup uint16_t words. */
4879                 0,                      /* max returned setup. */
4880                 NULL,                   /* param. */
4881                 0,                      /* num param. */
4882                 buffer_size,            /* max returned param. */
4883                 NULL,                   /* data. */
4884                 0,                      /* num data. */
4885                 0);                     /* max returned data. */
4886
4887         if (tevent_req_nomem(subreq, req)) {
4888                 return tevent_req_post(req, ev);
4889         }
4890         tevent_req_set_callback(subreq, cli_notify_done, req);
4891         return req;
4892 }
4893
4894 static void cli_notify_done(struct tevent_req *subreq)
4895 {
4896         struct tevent_req *req = tevent_req_callback_data(
4897                 subreq, struct tevent_req);
4898         struct cli_notify_state *state = tevent_req_data(
4899                 req, struct cli_notify_state);
4900         NTSTATUS status;
4901         uint8_t *params;
4902         uint32_t i, ofs, num_params;
4903         uint16_t flags2;
4904
4905         status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
4906                                 &params, 0, &num_params, NULL, 0, NULL);
4907         TALLOC_FREE(subreq);
4908         if (!NT_STATUS_IS_OK(status)) {
4909                 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
4910                 tevent_req_nterror(req, status);
4911                 return;
4912         }
4913
4914         state->num_changes = 0;
4915         ofs = 0;
4916
4917         while (num_params - ofs > 12) {
4918                 uint32_t len = IVAL(params, ofs);
4919                 state->num_changes += 1;
4920
4921                 if ((len == 0) || (ofs+len >= num_params)) {
4922                         break;
4923                 }
4924                 ofs += len;
4925         }
4926
4927         state->changes = talloc_array(state, struct notify_change,
4928                                       state->num_changes);
4929         if (tevent_req_nomem(state->changes, req)) {
4930                 TALLOC_FREE(params);
4931                 return;
4932         }
4933
4934         ofs = 0;
4935
4936         for (i=0; i<state->num_changes; i++) {
4937                 uint32_t next = IVAL(params, ofs);
4938                 uint32_t len = IVAL(params, ofs+8);
4939                 ssize_t ret;
4940                 char *name;
4941
4942                 if ((next != 0) && (len+12 != next)) {
4943                         TALLOC_FREE(params);
4944                         tevent_req_nterror(
4945                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
4946                         return;
4947                 }
4948
4949                 state->changes[i].action = IVAL(params, ofs+4);
4950                 ret = clistr_pull_talloc(params, (char *)params, flags2,
4951                                          &name, params+ofs+12, len,
4952                                          STR_TERMINATE|STR_UNICODE);
4953                 if (ret == -1) {
4954                         TALLOC_FREE(params);
4955                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
4956                         return;
4957                 }
4958                 state->changes[i].name = name;
4959                 ofs += next;
4960         }
4961
4962         TALLOC_FREE(params);
4963         tevent_req_done(req);
4964 }
4965
4966 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4967                          uint32_t *pnum_changes,
4968                          struct notify_change **pchanges)
4969 {
4970         struct cli_notify_state *state = tevent_req_data(
4971                 req, struct cli_notify_state);
4972         NTSTATUS status;
4973
4974         if (tevent_req_is_nterror(req, &status)) {
4975                 return status;
4976         }
4977
4978         *pnum_changes = state->num_changes;
4979         *pchanges = talloc_move(mem_ctx, &state->changes);
4980         return NT_STATUS_OK;
4981 }
4982
4983 struct cli_qpathinfo_state {
4984         uint8_t *param;
4985         uint8_t *data;
4986         uint16_t setup[1];
4987         uint32_t min_rdata;
4988         uint8_t *rdata;
4989         uint32_t num_rdata;
4990 };
4991
4992 static void cli_qpathinfo_done(struct tevent_req *subreq);
4993
4994 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
4995                                       struct tevent_context *ev,
4996                                       struct cli_state *cli, const char *fname,
4997                                       uint16_t level, uint32_t min_rdata,
4998                                       uint32_t max_rdata)
4999 {
5000         struct tevent_req *req, *subreq;
5001         struct cli_qpathinfo_state *state;
5002
5003         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
5004         if (req == NULL) {
5005                 return NULL;
5006         }
5007         state->min_rdata = min_rdata;
5008         SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
5009
5010         state->param = talloc_zero_array(state, uint8_t, 6);
5011         if (tevent_req_nomem(state->param, req)) {
5012                 return tevent_req_post(req, ev);
5013         }
5014         SSVAL(state->param, 0, level);
5015         state->param = trans2_bytes_push_str(
5016                 state->param, cli_ucs2(cli), fname, strlen(fname)+1, NULL);
5017         if (tevent_req_nomem(state->param, req)) {
5018                 return tevent_req_post(req, ev);
5019         }
5020
5021         subreq = cli_trans_send(
5022                 state,                  /* mem ctx. */
5023                 ev,                     /* event ctx. */
5024                 cli,                    /* cli_state. */
5025                 SMBtrans2,              /* cmd. */
5026                 NULL,                   /* pipe name. */
5027                 -1,                     /* fid. */
5028                 0,                      /* function. */
5029                 0,                      /* flags. */
5030                 state->setup,           /* setup. */
5031                 1,                      /* num setup uint16_t words. */
5032                 0,                      /* max returned setup. */
5033                 state->param,           /* param. */
5034                 talloc_get_size(state->param),  /* num param. */
5035                 2,                      /* max returned param. */
5036                 NULL,                   /* data. */
5037                 0,                      /* num data. */
5038                 max_rdata);             /* max returned data. */
5039
5040         if (tevent_req_nomem(subreq, req)) {
5041                 return tevent_req_post(req, ev);
5042         }
5043         tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5044         return req;
5045 }
5046
5047 static void cli_qpathinfo_done(struct tevent_req *subreq)
5048 {
5049         struct tevent_req *req = tevent_req_callback_data(
5050                 subreq, struct tevent_req);
5051         struct cli_qpathinfo_state *state = tevent_req_data(
5052                 req, struct cli_qpathinfo_state);
5053         NTSTATUS status;
5054
5055         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5056                                 NULL, 0, NULL,
5057                                 &state->rdata, state->min_rdata,
5058                                 &state->num_rdata);
5059         if (!NT_STATUS_IS_OK(status)) {
5060                 tevent_req_nterror(req, status);
5061                 return;
5062         }
5063         tevent_req_done(req);
5064 }
5065
5066 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5067                             uint8_t **rdata, uint32_t *num_rdata)
5068 {
5069         struct cli_qpathinfo_state *state = tevent_req_data(
5070                 req, struct cli_qpathinfo_state);
5071         NTSTATUS status;
5072
5073         if (tevent_req_is_nterror(req, &status)) {
5074                 return status;
5075         }
5076         if (rdata != NULL) {
5077                 *rdata = talloc_move(mem_ctx, &state->rdata);
5078         } else {
5079                 TALLOC_FREE(state->rdata);
5080         }
5081         if (num_rdata != NULL) {
5082                 *num_rdata = state->num_rdata;
5083         }
5084         return NT_STATUS_OK;
5085 }
5086
5087 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5088                        const char *fname, uint16_t level, uint32_t min_rdata,
5089                        uint32_t max_rdata,
5090                        uint8_t **rdata, uint32_t *num_rdata)
5091 {
5092         TALLOC_CTX *frame = talloc_stackframe();
5093         struct event_context *ev;
5094         struct tevent_req *req;
5095         NTSTATUS status = NT_STATUS_NO_MEMORY;
5096
5097         if (cli_has_async_calls(cli)) {
5098                 /*
5099                  * Can't use sync call while an async call is in flight
5100                  */
5101                 status = NT_STATUS_INVALID_PARAMETER;
5102                 goto fail;
5103         }
5104         ev = event_context_init(frame);
5105         if (ev == NULL) {
5106                 goto fail;
5107         }
5108         req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5109                                  max_rdata);
5110         if (req == NULL) {
5111                 goto fail;
5112         }
5113         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5114                 goto fail;
5115         }
5116         status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5117  fail:
5118         TALLOC_FREE(frame);
5119         if (!NT_STATUS_IS_OK(status)) {
5120                 cli_set_error(cli, status);
5121         }
5122         return status;
5123 }
5124
5125 struct cli_qfileinfo_state {
5126         uint16_t setup[1];
5127         uint8_t param[4];
5128         uint8_t *data;
5129         uint32_t min_rdata;
5130         uint8_t *rdata;
5131         uint32_t num_rdata;
5132 };
5133
5134 static void cli_qfileinfo_done(struct tevent_req *subreq);
5135
5136 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
5137                                       struct tevent_context *ev,
5138                                       struct cli_state *cli, uint16_t fnum,
5139                                       uint16_t level, uint32_t min_rdata,
5140                                       uint32_t max_rdata)
5141 {
5142         struct tevent_req *req, *subreq;
5143         struct cli_qfileinfo_state *state;
5144
5145         req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
5146         if (req == NULL) {
5147                 return NULL;
5148         }
5149         state->min_rdata = min_rdata;
5150         SSVAL(state->param, 0, fnum);
5151         SSVAL(state->param, 2, level);
5152         SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
5153
5154         subreq = cli_trans_send(
5155                 state,                  /* mem ctx. */
5156                 ev,                     /* event ctx. */
5157                 cli,                    /* cli_state. */
5158                 SMBtrans2,              /* cmd. */
5159                 NULL,                   /* pipe name. */
5160                 -1,                     /* fid. */
5161                 0,                      /* function. */
5162                 0,                      /* flags. */
5163                 state->setup,           /* setup. */
5164                 1,                      /* num setup uint16_t words. */
5165                 0,                      /* max returned setup. */
5166                 state->param,           /* param. */
5167                 sizeof(state->param),   /* num param. */
5168                 2,                      /* max returned param. */
5169                 NULL,                   /* data. */
5170                 0,                      /* num data. */
5171                 max_rdata);             /* max returned data. */
5172
5173         if (tevent_req_nomem(subreq, req)) {
5174                 return tevent_req_post(req, ev);
5175         }
5176         tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
5177         return req;
5178 }
5179
5180 static void cli_qfileinfo_done(struct tevent_req *subreq)
5181 {
5182         struct tevent_req *req = tevent_req_callback_data(
5183                 subreq, struct tevent_req);
5184         struct cli_qfileinfo_state *state = tevent_req_data(
5185                 req, struct cli_qfileinfo_state);
5186         NTSTATUS status;
5187
5188         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5189                                 NULL, 0, NULL,
5190                                 &state->rdata, state->min_rdata,
5191                                 &state->num_rdata);
5192         if (!NT_STATUS_IS_OK(status)) {
5193                 tevent_req_nterror(req, status);
5194                 return;
5195         }
5196         tevent_req_done(req);
5197 }
5198
5199 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5200                             uint8_t **rdata, uint32_t *num_rdata)
5201 {
5202         struct cli_qfileinfo_state *state = tevent_req_data(
5203                 req, struct cli_qfileinfo_state);
5204         NTSTATUS status;
5205
5206         if (tevent_req_is_nterror(req, &status)) {
5207                 return status;
5208         }
5209         if (rdata != NULL) {
5210                 *rdata = talloc_move(mem_ctx, &state->rdata);
5211         } else {
5212                 TALLOC_FREE(state->rdata);
5213         }
5214         if (num_rdata != NULL) {
5215                 *num_rdata = state->num_rdata;
5216         }
5217         return NT_STATUS_OK;
5218 }
5219
5220 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5221                        uint16_t fnum, uint16_t level, uint32_t min_rdata,
5222                        uint32_t max_rdata,
5223                        uint8_t **rdata, uint32_t *num_rdata)
5224 {
5225         TALLOC_CTX *frame = talloc_stackframe();
5226         struct event_context *ev;
5227         struct tevent_req *req;
5228         NTSTATUS status = NT_STATUS_NO_MEMORY;
5229
5230         if (cli_has_async_calls(cli)) {
5231                 /*
5232                  * Can't use sync call while an async call is in flight
5233                  */
5234                 status = NT_STATUS_INVALID_PARAMETER;
5235                 goto fail;
5236         }
5237         ev = event_context_init(frame);
5238         if (ev == NULL) {
5239                 goto fail;
5240         }
5241         req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
5242                                  max_rdata);
5243         if (req == NULL) {
5244                 goto fail;
5245         }
5246         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5247                 goto fail;
5248         }
5249         status = cli_qfileinfo_recv(req, mem_ctx, rdata, num_rdata);
5250  fail:
5251         TALLOC_FREE(frame);
5252         if (!NT_STATUS_IS_OK(status)) {
5253                 cli_set_error(cli, status);
5254         }
5255         return status;
5256 }
5257
5258 struct cli_flush_state {
5259         uint16_t vwv[1];
5260 };
5261
5262 static void cli_flush_done(struct tevent_req *subreq);
5263
5264 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
5265                                   struct event_context *ev,
5266                                   struct cli_state *cli,
5267                                   uint16_t fnum)
5268 {
5269         struct tevent_req *req, *subreq;
5270         struct cli_flush_state *state;
5271
5272         req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
5273         if (req == NULL) {
5274                 return NULL;
5275         }
5276         SSVAL(state->vwv + 0, 0, fnum);
5277
5278         subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 1, state->vwv,
5279                               0, NULL);
5280         if (tevent_req_nomem(subreq, req)) {
5281                 return tevent_req_post(req, ev);
5282         }
5283         tevent_req_set_callback(subreq, cli_flush_done, req);
5284         return req;
5285 }
5286
5287 static void cli_flush_done(struct tevent_req *subreq)
5288 {
5289         struct tevent_req *req = tevent_req_callback_data(
5290                 subreq, struct tevent_req);
5291         NTSTATUS status;
5292
5293         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5294         TALLOC_FREE(subreq);
5295         if (!NT_STATUS_IS_OK(status)) {
5296                 tevent_req_nterror(req, status);
5297                 return;
5298         }
5299         tevent_req_done(req);
5300 }
5301
5302 NTSTATUS cli_flush_recv(struct tevent_req *req)
5303 {
5304         return tevent_req_simple_recv_ntstatus(req);
5305 }
5306
5307 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
5308 {
5309         TALLOC_CTX *frame = talloc_stackframe();
5310         struct event_context *ev;
5311         struct tevent_req *req;
5312         NTSTATUS status = NT_STATUS_NO_MEMORY;
5313
5314         if (cli_has_async_calls(cli)) {
5315                 /*
5316                  * Can't use sync call while an async call is in flight
5317                  */
5318                 status = NT_STATUS_INVALID_PARAMETER;
5319                 goto fail;
5320         }
5321         ev = event_context_init(frame);
5322         if (ev == NULL) {
5323                 goto fail;
5324         }
5325         req = cli_flush_send(frame, ev, cli, fnum);
5326         if (req == NULL) {
5327                 goto fail;
5328         }
5329         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5330                 goto fail;
5331         }
5332         status = cli_flush_recv(req);
5333  fail:
5334         TALLOC_FREE(frame);
5335         if (!NT_STATUS_IS_OK(status)) {
5336                 cli_set_error(cli, status);
5337         }
5338         return status;
5339 }