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