Make cli_posix_stat() async.
[samba.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
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 static bool cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname, uint32_t mode, uint32_t uid, uint32_t gid)
950 {
951         unsigned int data_len = 0;
952         unsigned int param_len = 0;
953         uint16_t setup = TRANSACT2_SETPATHINFO;
954         size_t nlen = 2*(strlen(fname)+1);
955         char *param;
956         char data[100];
957         char *rparam=NULL, *rdata=NULL;
958         char *p;
959
960         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
961         if (!param) {
962                 return false;
963         }
964         memset(param, '\0', 6);
965         memset(data, 0, sizeof(data));
966
967         SSVAL(param,0,SMB_SET_FILE_UNIX_BASIC);
968         p = &param[6];
969
970         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
971         param_len = PTR_DIFF(p, param);
972
973         memset(data, 0xff, 40); /* Set all sizes/times to no change. */
974
975         SIVAL(data,40,uid);
976         SIVAL(data,48,gid);
977         SIVAL(data,84,mode);
978
979         data_len = 100;
980
981         if (!cli_send_trans(cli, SMBtrans2,
982                         NULL,                        /* name */
983                         -1, 0,                          /* fid, flags */
984                         &setup, 1, 0,                   /* setup, length, max */
985                         param, param_len, 2,            /* param, length, max */
986                         (char *)&data,  data_len, cli->max_xmit /* data, length, max */
987                         )) {
988                 SAFE_FREE(param);
989                 return False;
990         }
991
992         SAFE_FREE(param);
993
994         if (!cli_receive_trans(cli, SMBtrans2,
995                         &rparam, &param_len,
996                         &rdata, &data_len)) {
997                 return false;
998         }
999
1000         SAFE_FREE(rdata);
1001         SAFE_FREE(rparam);
1002
1003         return true;
1004 }
1005
1006 /****************************************************************************
1007  chmod a file (UNIX extensions).
1008 ****************************************************************************/
1009
1010 bool cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
1011 {
1012         return cli_unix_chmod_chown_internal(cli, fname,
1013                 unix_perms_to_wire(mode), SMB_UID_NO_CHANGE, SMB_GID_NO_CHANGE);
1014 }
1015
1016 /****************************************************************************
1017  chown a file (UNIX extensions).
1018 ****************************************************************************/
1019
1020 bool cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid)
1021 {
1022         return cli_unix_chmod_chown_internal(cli, fname,
1023                         SMB_MODE_NO_CHANGE, (uint32)uid, (uint32)gid);
1024 }
1025
1026 /****************************************************************************
1027  Rename a file.
1028 ****************************************************************************/
1029
1030 static void cli_rename_done(struct tevent_req *subreq);
1031
1032 struct cli_rename_state {
1033         uint16_t vwv[1];
1034 };
1035
1036 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1037                                 struct event_context *ev,
1038                                 struct cli_state *cli,
1039                                 const char *fname_src,
1040                                 const char *fname_dst)
1041 {
1042         struct tevent_req *req = NULL, *subreq = NULL;
1043         struct cli_rename_state *state = NULL;
1044         uint8_t additional_flags = 0;
1045         uint8_t *bytes = NULL;
1046
1047         req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1048         if (req == NULL) {
1049                 return NULL;
1050         }
1051
1052         SSVAL(state->vwv+0, 0, aSYSTEM | aHIDDEN | aDIR);
1053
1054         bytes = talloc_array(state, uint8_t, 1);
1055         if (tevent_req_nomem(bytes, req)) {
1056                 return tevent_req_post(req, ev);
1057         }
1058         bytes[0] = 4;
1059         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1060                                    strlen(fname_src)+1, NULL);
1061         if (tevent_req_nomem(bytes, req)) {
1062                 return tevent_req_post(req, ev);
1063         }
1064
1065         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1066                         talloc_get_size(bytes)+1);
1067         if (tevent_req_nomem(bytes, req)) {
1068                 return tevent_req_post(req, ev);
1069         }
1070
1071         bytes[talloc_get_size(bytes)-1] = 4;
1072         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1073                                    strlen(fname_dst)+1, NULL);
1074         if (tevent_req_nomem(bytes, req)) {
1075                 return tevent_req_post(req, ev);
1076         }
1077
1078         subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1079                               1, state->vwv, talloc_get_size(bytes), bytes);
1080         if (tevent_req_nomem(subreq, req)) {
1081                 return tevent_req_post(req, ev);
1082         }
1083         tevent_req_set_callback(subreq, cli_rename_done, req);
1084         return req;
1085 }
1086
1087 static void cli_rename_done(struct tevent_req *subreq)
1088 {
1089         struct tevent_req *req = tevent_req_callback_data(
1090                                 subreq, struct tevent_req);
1091         NTSTATUS status;
1092
1093         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1094         TALLOC_FREE(subreq);
1095         if (!NT_STATUS_IS_OK(status)) {
1096                 tevent_req_nterror(req, status);
1097                 return;
1098         }
1099         tevent_req_done(req);
1100 }
1101
1102 NTSTATUS cli_rename_recv(struct tevent_req *req)
1103 {
1104         return tevent_req_simple_recv_ntstatus(req);
1105 }
1106
1107 NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1108 {
1109         TALLOC_CTX *frame = talloc_stackframe();
1110         struct event_context *ev;
1111         struct tevent_req *req;
1112         NTSTATUS status = NT_STATUS_OK;
1113
1114         if (cli_has_async_calls(cli)) {
1115                 /*
1116                  * Can't use sync call while an async call is in flight
1117                  */
1118                 status = NT_STATUS_INVALID_PARAMETER;
1119                 goto fail;
1120         }
1121
1122         ev = event_context_init(frame);
1123         if (ev == NULL) {
1124                 status = NT_STATUS_NO_MEMORY;
1125                 goto fail;
1126         }
1127
1128         req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
1129         if (req == NULL) {
1130                 status = NT_STATUS_NO_MEMORY;
1131                 goto fail;
1132         }
1133
1134         if (!tevent_req_poll(req, ev)) {
1135                 status = map_nt_error_from_unix(errno);
1136                 goto fail;
1137         }
1138
1139         status = cli_rename_recv(req);
1140
1141  fail:
1142         TALLOC_FREE(frame);
1143         if (!NT_STATUS_IS_OK(status)) {
1144                 cli_set_error(cli, status);
1145         }
1146         return status;
1147 }
1148
1149 /****************************************************************************
1150  NT Rename a file.
1151 ****************************************************************************/
1152
1153 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1154
1155 struct cli_ntrename_internal_state {
1156         uint16_t vwv[4];
1157 };
1158
1159 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1160                                 struct event_context *ev,
1161                                 struct cli_state *cli,
1162                                 const char *fname_src,
1163                                 const char *fname_dst,
1164                                 uint16_t rename_flag)
1165 {
1166         struct tevent_req *req = NULL, *subreq = NULL;
1167         struct cli_ntrename_internal_state *state = NULL;
1168         uint8_t additional_flags = 0;
1169         uint8_t *bytes = NULL;
1170
1171         req = tevent_req_create(mem_ctx, &state,
1172                                 struct cli_ntrename_internal_state);
1173         if (req == NULL) {
1174                 return NULL;
1175         }
1176
1177         SSVAL(state->vwv+0, 0 ,aSYSTEM | aHIDDEN | aDIR);
1178         SSVAL(state->vwv+1, 0, rename_flag);
1179
1180         bytes = talloc_array(state, uint8_t, 1);
1181         if (tevent_req_nomem(bytes, req)) {
1182                 return tevent_req_post(req, ev);
1183         }
1184         bytes[0] = 4;
1185         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1186                                    strlen(fname_src)+1, NULL);
1187         if (tevent_req_nomem(bytes, req)) {
1188                 return tevent_req_post(req, ev);
1189         }
1190
1191         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1192                         talloc_get_size(bytes)+1);
1193         if (tevent_req_nomem(bytes, req)) {
1194                 return tevent_req_post(req, ev);
1195         }
1196
1197         bytes[talloc_get_size(bytes)-1] = 4;
1198         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1199                                    strlen(fname_dst)+1, NULL);
1200         if (tevent_req_nomem(bytes, req)) {
1201                 return tevent_req_post(req, ev);
1202         }
1203
1204         subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1205                               4, state->vwv, talloc_get_size(bytes), bytes);
1206         if (tevent_req_nomem(subreq, req)) {
1207                 return tevent_req_post(req, ev);
1208         }
1209         tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1210         return req;
1211 }
1212
1213 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1214 {
1215         struct tevent_req *req = tevent_req_callback_data(
1216                                 subreq, struct tevent_req);
1217         NTSTATUS status;
1218
1219         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1220         TALLOC_FREE(subreq);
1221         if (!NT_STATUS_IS_OK(status)) {
1222                 tevent_req_nterror(req, status);
1223                 return;
1224         }
1225         tevent_req_done(req);
1226 }
1227
1228 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1229 {
1230         return tevent_req_simple_recv_ntstatus(req);
1231 }
1232
1233 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1234                                 struct event_context *ev,
1235                                 struct cli_state *cli,
1236                                 const char *fname_src,
1237                                 const char *fname_dst)
1238 {
1239         return cli_ntrename_internal_send(mem_ctx,
1240                                           ev,
1241                                           cli,
1242                                           fname_src,
1243                                           fname_dst,
1244                                           RENAME_FLAG_RENAME);
1245 }
1246
1247 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1248 {
1249         return cli_ntrename_internal_recv(req);
1250 }
1251
1252 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1253 {
1254         TALLOC_CTX *frame = talloc_stackframe();
1255         struct event_context *ev;
1256         struct tevent_req *req;
1257         NTSTATUS status = NT_STATUS_OK;
1258
1259         if (cli_has_async_calls(cli)) {
1260                 /*
1261                  * Can't use sync call while an async call is in flight
1262                  */
1263                 status = NT_STATUS_INVALID_PARAMETER;
1264                 goto fail;
1265         }
1266
1267         ev = event_context_init(frame);
1268         if (ev == NULL) {
1269                 status = NT_STATUS_NO_MEMORY;
1270                 goto fail;
1271         }
1272
1273         req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1274         if (req == NULL) {
1275                 status = NT_STATUS_NO_MEMORY;
1276                 goto fail;
1277         }
1278
1279         if (!tevent_req_poll(req, ev)) {
1280                 status = map_nt_error_from_unix(errno);
1281                 goto fail;
1282         }
1283
1284         status = cli_ntrename_recv(req);
1285
1286  fail:
1287         TALLOC_FREE(frame);
1288         if (!NT_STATUS_IS_OK(status)) {
1289                 cli_set_error(cli, status);
1290         }
1291         return status;
1292 }
1293
1294 /****************************************************************************
1295  NT hardlink a file.
1296 ****************************************************************************/
1297
1298 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1299                                 struct event_context *ev,
1300                                 struct cli_state *cli,
1301                                 const char *fname_src,
1302                                 const char *fname_dst)
1303 {
1304         return cli_ntrename_internal_send(mem_ctx,
1305                                           ev,
1306                                           cli,
1307                                           fname_src,
1308                                           fname_dst,
1309                                           RENAME_FLAG_HARD_LINK);
1310 }
1311
1312 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1313 {
1314         return cli_ntrename_internal_recv(req);
1315 }
1316
1317 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1318 {
1319         TALLOC_CTX *frame = talloc_stackframe();
1320         struct event_context *ev;
1321         struct tevent_req *req;
1322         NTSTATUS status = NT_STATUS_OK;
1323
1324         if (cli_has_async_calls(cli)) {
1325                 /*
1326                  * Can't use sync call while an async call is in flight
1327                  */
1328                 status = NT_STATUS_INVALID_PARAMETER;
1329                 goto fail;
1330         }
1331
1332         ev = event_context_init(frame);
1333         if (ev == NULL) {
1334                 status = NT_STATUS_NO_MEMORY;
1335                 goto fail;
1336         }
1337
1338         req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1339         if (req == NULL) {
1340                 status = NT_STATUS_NO_MEMORY;
1341                 goto fail;
1342         }
1343
1344         if (!tevent_req_poll(req, ev)) {
1345                 status = map_nt_error_from_unix(errno);
1346                 goto fail;
1347         }
1348
1349         status = cli_nt_hardlink_recv(req);
1350
1351  fail:
1352         TALLOC_FREE(frame);
1353         if (!NT_STATUS_IS_OK(status)) {
1354                 cli_set_error(cli, status);
1355         }
1356         return status;
1357 }
1358
1359 /****************************************************************************
1360  Delete a file.
1361 ****************************************************************************/
1362
1363 static void cli_unlink_done(struct tevent_req *subreq);
1364
1365 struct cli_unlink_state {
1366         uint16_t vwv[1];
1367 };
1368
1369 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1370                                 struct event_context *ev,
1371                                 struct cli_state *cli,
1372                                 const char *fname,
1373                                 uint16_t mayhave_attrs)
1374 {
1375         struct tevent_req *req = NULL, *subreq = NULL;
1376         struct cli_unlink_state *state = NULL;
1377         uint8_t additional_flags = 0;
1378         uint8_t *bytes = NULL;
1379
1380         req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1381         if (req == NULL) {
1382                 return NULL;
1383         }
1384
1385         SSVAL(state->vwv+0, 0, mayhave_attrs);
1386
1387         bytes = talloc_array(state, uint8_t, 1);
1388         if (tevent_req_nomem(bytes, req)) {
1389                 return tevent_req_post(req, ev);
1390         }
1391         bytes[0] = 4;
1392         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
1393                                    strlen(fname)+1, NULL);
1394
1395         if (tevent_req_nomem(bytes, req)) {
1396                 return tevent_req_post(req, ev);
1397         }
1398
1399         subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1400                                 1, state->vwv, talloc_get_size(bytes), bytes);
1401         if (tevent_req_nomem(subreq, req)) {
1402                 return tevent_req_post(req, ev);
1403         }
1404         tevent_req_set_callback(subreq, cli_unlink_done, req);
1405         return req;
1406 }
1407
1408 static void cli_unlink_done(struct tevent_req *subreq)
1409 {
1410         struct tevent_req *req = tevent_req_callback_data(
1411                 subreq, struct tevent_req);
1412         NTSTATUS status;
1413
1414         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1415         TALLOC_FREE(subreq);
1416         if (!NT_STATUS_IS_OK(status)) {
1417                 tevent_req_nterror(req, status);
1418                 return;
1419         }
1420         tevent_req_done(req);
1421 }
1422
1423 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1424 {
1425         return tevent_req_simple_recv_ntstatus(req);
1426 }
1427
1428 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1429 {
1430         TALLOC_CTX *frame = talloc_stackframe();
1431         struct event_context *ev;
1432         struct tevent_req *req;
1433         NTSTATUS status = NT_STATUS_OK;
1434
1435         if (cli_has_async_calls(cli)) {
1436                 /*
1437                  * Can't use sync call while an async call is in flight
1438                  */
1439                 status = NT_STATUS_INVALID_PARAMETER;
1440                 goto fail;
1441         }
1442
1443         ev = event_context_init(frame);
1444         if (ev == NULL) {
1445                 status = NT_STATUS_NO_MEMORY;
1446                 goto fail;
1447         }
1448
1449         req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1450         if (req == NULL) {
1451                 status = NT_STATUS_NO_MEMORY;
1452                 goto fail;
1453         }
1454
1455         if (!tevent_req_poll(req, ev)) {
1456                 status = map_nt_error_from_unix(errno);
1457                 goto fail;
1458         }
1459
1460         status = cli_unlink_recv(req);
1461
1462  fail:
1463         TALLOC_FREE(frame);
1464         if (!NT_STATUS_IS_OK(status)) {
1465                 cli_set_error(cli, status);
1466         }
1467         return status;
1468 }
1469
1470 /****************************************************************************
1471  Create a directory.
1472 ****************************************************************************/
1473
1474 static void cli_mkdir_done(struct tevent_req *subreq);
1475
1476 struct cli_mkdir_state {
1477         int dummy;
1478 };
1479
1480 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1481                                   struct event_context *ev,
1482                                   struct cli_state *cli,
1483                                   const char *dname)
1484 {
1485         struct tevent_req *req = NULL, *subreq = NULL;
1486         struct cli_mkdir_state *state = NULL;
1487         uint8_t additional_flags = 0;
1488         uint8_t *bytes = NULL;
1489
1490         req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1491         if (req == NULL) {
1492                 return NULL;
1493         }
1494
1495         bytes = talloc_array(state, uint8_t, 1);
1496         if (tevent_req_nomem(bytes, req)) {
1497                 return tevent_req_post(req, ev);
1498         }
1499         bytes[0] = 4;
1500         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1501                                    strlen(dname)+1, NULL);
1502
1503         if (tevent_req_nomem(bytes, req)) {
1504                 return tevent_req_post(req, ev);
1505         }
1506
1507         subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1508                               0, NULL, talloc_get_size(bytes), bytes);
1509         if (tevent_req_nomem(subreq, req)) {
1510                 return tevent_req_post(req, ev);
1511         }
1512         tevent_req_set_callback(subreq, cli_mkdir_done, req);
1513         return req;
1514 }
1515
1516 static void cli_mkdir_done(struct tevent_req *subreq)
1517 {
1518         struct tevent_req *req = tevent_req_callback_data(
1519                 subreq, struct tevent_req);
1520         NTSTATUS status;
1521
1522         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1523         TALLOC_FREE(subreq);
1524         if (!NT_STATUS_IS_OK(status)) {
1525                 tevent_req_nterror(req, status);
1526                 return;
1527         }
1528         tevent_req_done(req);
1529 }
1530
1531 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1532 {
1533         return tevent_req_simple_recv_ntstatus(req);
1534 }
1535
1536 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1537 {
1538         TALLOC_CTX *frame = talloc_stackframe();
1539         struct event_context *ev;
1540         struct tevent_req *req;
1541         NTSTATUS status = NT_STATUS_OK;
1542
1543         if (cli_has_async_calls(cli)) {
1544                 /*
1545                  * Can't use sync call while an async call is in flight
1546                  */
1547                 status = NT_STATUS_INVALID_PARAMETER;
1548                 goto fail;
1549         }
1550
1551         ev = event_context_init(frame);
1552         if (ev == NULL) {
1553                 status = NT_STATUS_NO_MEMORY;
1554                 goto fail;
1555         }
1556
1557         req = cli_mkdir_send(frame, ev, cli, dname);
1558         if (req == NULL) {
1559                 status = NT_STATUS_NO_MEMORY;
1560                 goto fail;
1561         }
1562
1563         if (!tevent_req_poll(req, ev)) {
1564                 status = map_nt_error_from_unix(errno);
1565                 goto fail;
1566         }
1567
1568         status = cli_mkdir_recv(req);
1569
1570  fail:
1571         TALLOC_FREE(frame);
1572         if (!NT_STATUS_IS_OK(status)) {
1573                 cli_set_error(cli, status);
1574         }
1575         return status;
1576 }
1577
1578 /****************************************************************************
1579  Remove a directory.
1580 ****************************************************************************/
1581
1582 static void cli_rmdir_done(struct tevent_req *subreq);
1583
1584 struct cli_rmdir_state {
1585         int dummy;
1586 };
1587
1588 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1589                                   struct event_context *ev,
1590                                   struct cli_state *cli,
1591                                   const char *dname)
1592 {
1593         struct tevent_req *req = NULL, *subreq = NULL;
1594         struct cli_rmdir_state *state = NULL;
1595         uint8_t additional_flags = 0;
1596         uint8_t *bytes = NULL;
1597
1598         req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1599         if (req == NULL) {
1600                 return NULL;
1601         }
1602
1603         bytes = talloc_array(state, uint8_t, 1);
1604         if (tevent_req_nomem(bytes, req)) {
1605                 return tevent_req_post(req, ev);
1606         }
1607         bytes[0] = 4;
1608         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1609                                    strlen(dname)+1, NULL);
1610
1611         if (tevent_req_nomem(bytes, req)) {
1612                 return tevent_req_post(req, ev);
1613         }
1614
1615         subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1616                               0, NULL, talloc_get_size(bytes), bytes);
1617         if (tevent_req_nomem(subreq, req)) {
1618                 return tevent_req_post(req, ev);
1619         }
1620         tevent_req_set_callback(subreq, cli_rmdir_done, req);
1621         return req;
1622 }
1623
1624 static void cli_rmdir_done(struct tevent_req *subreq)
1625 {
1626         struct tevent_req *req = tevent_req_callback_data(
1627                 subreq, struct tevent_req);
1628         NTSTATUS status;
1629
1630         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1631         TALLOC_FREE(subreq);
1632         if (!NT_STATUS_IS_OK(status)) {
1633                 tevent_req_nterror(req, status);
1634                 return;
1635         }
1636         tevent_req_done(req);
1637 }
1638
1639 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1640 {
1641         return tevent_req_simple_recv_ntstatus(req);
1642 }
1643
1644 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1645 {
1646         TALLOC_CTX *frame = talloc_stackframe();
1647         struct event_context *ev;
1648         struct tevent_req *req;
1649         NTSTATUS status = NT_STATUS_OK;
1650
1651         if (cli_has_async_calls(cli)) {
1652                 /*
1653                  * Can't use sync call while an async call is in flight
1654                  */
1655                 status = NT_STATUS_INVALID_PARAMETER;
1656                 goto fail;
1657         }
1658
1659         ev = event_context_init(frame);
1660         if (ev == NULL) {
1661                 status = NT_STATUS_NO_MEMORY;
1662                 goto fail;
1663         }
1664
1665         req = cli_rmdir_send(frame, ev, cli, dname);
1666         if (req == NULL) {
1667                 status = NT_STATUS_NO_MEMORY;
1668                 goto fail;
1669         }
1670
1671         if (!tevent_req_poll(req, ev)) {
1672                 status = map_nt_error_from_unix(errno);
1673                 goto fail;
1674         }
1675
1676         status = cli_rmdir_recv(req);
1677
1678  fail:
1679         TALLOC_FREE(frame);
1680         if (!NT_STATUS_IS_OK(status)) {
1681                 cli_set_error(cli, status);
1682         }
1683         return status;
1684 }
1685
1686 /****************************************************************************
1687  Set or clear the delete on close flag.
1688 ****************************************************************************/
1689
1690 int cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1691 {
1692         unsigned int data_len = 1;
1693         unsigned int param_len = 6;
1694         uint16_t setup = TRANSACT2_SETFILEINFO;
1695         char param[6];
1696         unsigned char data;
1697         char *rparam=NULL, *rdata=NULL;
1698
1699         memset(param, 0, param_len);
1700         SSVAL(param,0,fnum);
1701         SSVAL(param,2,SMB_SET_FILE_DISPOSITION_INFO);
1702
1703         data = flag ? 1 : 0;
1704
1705         if (!cli_send_trans(cli, SMBtrans2,
1706                         NULL,                        /* name */
1707                         -1, 0,                          /* fid, flags */
1708                         &setup, 1, 0,                   /* setup, length, max */
1709                         param, param_len, 2,            /* param, length, max */
1710                         (char *)&data,  data_len, cli->max_xmit /* data, length, max */
1711                         )) {
1712                 return false;
1713         }
1714
1715         if (!cli_receive_trans(cli, SMBtrans2,
1716                         &rparam, &param_len,
1717                         &rdata, &data_len)) {
1718                 return false;
1719         }
1720
1721         SAFE_FREE(rdata);
1722         SAFE_FREE(rparam);
1723
1724         return true;
1725 }
1726
1727 struct cli_ntcreate_state {
1728         uint16_t vwv[24];
1729         uint16_t fnum;
1730 };
1731
1732 static void cli_ntcreate_done(struct tevent_req *subreq);
1733
1734 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
1735                                      struct event_context *ev,
1736                                      struct cli_state *cli,
1737                                      const char *fname,
1738                                      uint32_t CreatFlags,
1739                                      uint32_t DesiredAccess,
1740                                      uint32_t FileAttributes,
1741                                      uint32_t ShareAccess,
1742                                      uint32_t CreateDisposition,
1743                                      uint32_t CreateOptions,
1744                                      uint8_t SecurityFlags)
1745 {
1746         struct tevent_req *req, *subreq;
1747         struct cli_ntcreate_state *state;
1748         uint16_t *vwv;
1749         uint8_t *bytes;
1750         size_t converted_len;
1751
1752         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
1753         if (req == NULL) {
1754                 return NULL;
1755         }
1756         vwv = state->vwv;
1757
1758         SCVAL(vwv+0, 0, 0xFF);
1759         SCVAL(vwv+0, 1, 0);
1760         SSVAL(vwv+1, 0, 0);
1761         SCVAL(vwv+2, 0, 0);
1762
1763         if (cli->use_oplocks) {
1764                 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1765         }
1766         SIVAL(vwv+3, 1, CreatFlags);
1767         SIVAL(vwv+5, 1, 0x0);   /* RootDirectoryFid */
1768         SIVAL(vwv+7, 1, DesiredAccess);
1769         SIVAL(vwv+9, 1, 0x0);   /* AllocationSize */
1770         SIVAL(vwv+11, 1, 0x0);  /* AllocationSize */
1771         SIVAL(vwv+13, 1, FileAttributes);
1772         SIVAL(vwv+15, 1, ShareAccess);
1773         SIVAL(vwv+17, 1, CreateDisposition);
1774         SIVAL(vwv+19, 1, CreateOptions);
1775         SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1776         SCVAL(vwv+23, 1, SecurityFlags);
1777
1778         bytes = talloc_array(state, uint8_t, 0);
1779         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
1780                                    fname, strlen(fname)+1,
1781                                    &converted_len);
1782
1783         /* sigh. this copes with broken netapp filer behaviour */
1784         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL);
1785
1786         if (tevent_req_nomem(bytes, req)) {
1787                 return tevent_req_post(req, ev);
1788         }
1789
1790         SIVAL(vwv+2, 1, converted_len);
1791
1792         subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
1793                               talloc_get_size(bytes), bytes);
1794         if (tevent_req_nomem(subreq, req)) {
1795                 return tevent_req_post(req, ev);
1796         }
1797         tevent_req_set_callback(subreq, cli_ntcreate_done, req);
1798         return req;
1799 }
1800
1801 static void cli_ntcreate_done(struct tevent_req *subreq)
1802 {
1803         struct tevent_req *req = tevent_req_callback_data(
1804                 subreq, struct tevent_req);
1805         struct cli_ntcreate_state *state = tevent_req_data(
1806                 req, struct cli_ntcreate_state);
1807         uint8_t wct;
1808         uint16_t *vwv;
1809         uint32_t num_bytes;
1810         uint8_t *bytes;
1811         NTSTATUS status;
1812
1813         status = cli_smb_recv(subreq, 3, &wct, &vwv, &num_bytes, &bytes);
1814         if (!NT_STATUS_IS_OK(status)) {
1815                 TALLOC_FREE(subreq);
1816                 tevent_req_nterror(req, status);
1817                 return;
1818         }
1819         state->fnum = SVAL(vwv+2, 1);
1820         tevent_req_done(req);
1821 }
1822
1823 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
1824 {
1825         struct cli_ntcreate_state *state = tevent_req_data(
1826                 req, struct cli_ntcreate_state);
1827         NTSTATUS status;
1828
1829         if (tevent_req_is_nterror(req, &status)) {
1830                 return status;
1831         }
1832         *pfnum = state->fnum;
1833         return NT_STATUS_OK;
1834 }
1835
1836 NTSTATUS cli_ntcreate(struct cli_state *cli,
1837                       const char *fname,
1838                       uint32_t CreatFlags,
1839                       uint32_t DesiredAccess,
1840                       uint32_t FileAttributes,
1841                       uint32_t ShareAccess,
1842                       uint32_t CreateDisposition,
1843                       uint32_t CreateOptions,
1844                       uint8_t SecurityFlags,
1845                       uint16_t *pfid)
1846 {
1847         TALLOC_CTX *frame = talloc_stackframe();
1848         struct event_context *ev;
1849         struct tevent_req *req;
1850         NTSTATUS status = NT_STATUS_OK;
1851
1852         if (cli_has_async_calls(cli)) {
1853                 /*
1854                  * Can't use sync call while an async call is in flight
1855                  */
1856                 status = NT_STATUS_INVALID_PARAMETER;
1857                 goto fail;
1858         }
1859
1860         ev = event_context_init(frame);
1861         if (ev == NULL) {
1862                 status = NT_STATUS_NO_MEMORY;
1863                 goto fail;
1864         }
1865
1866         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
1867                                 DesiredAccess, FileAttributes, ShareAccess,
1868                                 CreateDisposition, CreateOptions,
1869                                 SecurityFlags);
1870         if (req == NULL) {
1871                 status = NT_STATUS_NO_MEMORY;
1872                 goto fail;
1873         }
1874
1875         if (!tevent_req_poll(req, ev)) {
1876                 status = map_nt_error_from_unix(errno);
1877                 goto fail;
1878         }
1879
1880         status = cli_ntcreate_recv(req, pfid);
1881  fail:
1882         TALLOC_FREE(frame);
1883         if (!NT_STATUS_IS_OK(status)) {
1884                 cli_set_error(cli, status);
1885         }
1886         return status;
1887 }
1888
1889 /****************************************************************************
1890  Open a file
1891  WARNING: if you open with O_WRONLY then getattrE won't work!
1892 ****************************************************************************/
1893
1894 struct cli_open_state {
1895         uint16_t vwv[15];
1896         uint16_t fnum;
1897         struct iovec bytes;
1898 };
1899
1900 static void cli_open_done(struct tevent_req *subreq);
1901
1902 struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx,
1903                                    struct event_context *ev,
1904                                    struct cli_state *cli, const char *fname,
1905                                    int flags, int share_mode,
1906                                    struct tevent_req **psmbreq)
1907 {
1908         struct tevent_req *req, *subreq;
1909         struct cli_open_state *state;
1910         unsigned openfn;
1911         unsigned accessmode;
1912         uint8_t additional_flags;
1913         uint8_t *bytes;
1914
1915         req = tevent_req_create(mem_ctx, &state, struct cli_open_state);
1916         if (req == NULL) {
1917                 return NULL;
1918         }
1919
1920         openfn = 0;
1921         if (flags & O_CREAT) {
1922                 openfn |= (1<<4);
1923         }
1924         if (!(flags & O_EXCL)) {
1925                 if (flags & O_TRUNC)
1926                         openfn |= (1<<1);
1927                 else
1928                         openfn |= (1<<0);
1929         }
1930
1931         accessmode = (share_mode<<4);
1932
1933         if ((flags & O_ACCMODE) == O_RDWR) {
1934                 accessmode |= 2;
1935         } else if ((flags & O_ACCMODE) == O_WRONLY) {
1936                 accessmode |= 1;
1937         }
1938
1939 #if defined(O_SYNC)
1940         if ((flags & O_SYNC) == O_SYNC) {
1941                 accessmode |= (1<<14);
1942         }
1943 #endif /* O_SYNC */
1944
1945         if (share_mode == DENY_FCB) {
1946                 accessmode = 0xFF;
1947         }
1948
1949         SCVAL(state->vwv + 0, 0, 0xFF);
1950         SCVAL(state->vwv + 0, 1, 0);
1951         SSVAL(state->vwv + 1, 0, 0);
1952         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
1953         SSVAL(state->vwv + 3, 0, accessmode);
1954         SSVAL(state->vwv + 4, 0, aSYSTEM | aHIDDEN);
1955         SSVAL(state->vwv + 5, 0, 0);
1956         SIVAL(state->vwv + 6, 0, 0);
1957         SSVAL(state->vwv + 8, 0, openfn);
1958         SIVAL(state->vwv + 9, 0, 0);
1959         SIVAL(state->vwv + 11, 0, 0);
1960         SIVAL(state->vwv + 13, 0, 0);
1961
1962         additional_flags = 0;
1963
1964         if (cli->use_oplocks) {
1965                 /* if using oplocks then ask for a batch oplock via
1966                    core and extended methods */
1967                 additional_flags =
1968                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
1969                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
1970         }
1971
1972         bytes = talloc_array(state, uint8_t, 0);
1973         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
1974                                    strlen(fname)+1, NULL);
1975
1976         if (tevent_req_nomem(bytes, req)) {
1977                 return tevent_req_post(req, ev);
1978         }
1979
1980         state->bytes.iov_base = (void *)bytes;
1981         state->bytes.iov_len = talloc_get_size(bytes);
1982
1983         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
1984                                     15, state->vwv, 1, &state->bytes);
1985         if (subreq == NULL) {
1986                 TALLOC_FREE(req);
1987                 return NULL;
1988         }
1989         tevent_req_set_callback(subreq, cli_open_done, req);
1990         *psmbreq = subreq;
1991         return req;
1992 }
1993
1994 struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
1995                                  struct cli_state *cli, const char *fname,
1996                                  int flags, int share_mode)
1997 {
1998         struct tevent_req *req, *subreq;
1999         NTSTATUS status;
2000
2001         req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode,
2002                               &subreq);
2003         if (req == NULL) {
2004                 return NULL;
2005         }
2006
2007         status = cli_smb_req_send(subreq);
2008         if (!NT_STATUS_IS_OK(status)) {
2009                 tevent_req_nterror(req, status);
2010                 return tevent_req_post(req, ev);
2011         }
2012         return req;
2013 }
2014
2015 static void cli_open_done(struct tevent_req *subreq)
2016 {
2017         struct tevent_req *req = tevent_req_callback_data(
2018                 subreq, struct tevent_req);
2019         struct cli_open_state *state = tevent_req_data(
2020                 req, struct cli_open_state);
2021         uint8_t wct;
2022         uint16_t *vwv;
2023         NTSTATUS status;
2024
2025         status = cli_smb_recv(subreq, 3, &wct, &vwv, NULL, NULL);
2026         if (!NT_STATUS_IS_OK(status)) {
2027                 TALLOC_FREE(subreq);
2028                 tevent_req_nterror(req, status);
2029                 return;
2030         }
2031         state->fnum = SVAL(vwv+2, 0);
2032         tevent_req_done(req);
2033 }
2034
2035 NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum)
2036 {
2037         struct cli_open_state *state = tevent_req_data(
2038                 req, struct cli_open_state);
2039         NTSTATUS status;
2040
2041         if (tevent_req_is_nterror(req, &status)) {
2042                 return status;
2043         }
2044         *pfnum = state->fnum;
2045         return NT_STATUS_OK;
2046 }
2047
2048 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2049              int share_mode, uint16_t *pfnum)
2050 {
2051         TALLOC_CTX *frame = talloc_stackframe();
2052         struct event_context *ev;
2053         struct tevent_req *req;
2054         NTSTATUS status = NT_STATUS_OK;
2055
2056         if (cli_has_async_calls(cli)) {
2057                 /*
2058                  * Can't use sync call while an async call is in flight
2059                  */
2060                 status = NT_STATUS_INVALID_PARAMETER;
2061                 goto fail;
2062         }
2063
2064         ev = event_context_init(frame);
2065         if (ev == NULL) {
2066                 status = NT_STATUS_NO_MEMORY;
2067                 goto fail;
2068         }
2069
2070         req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
2071         if (req == NULL) {
2072                 status = NT_STATUS_NO_MEMORY;
2073                 goto fail;
2074         }
2075
2076         if (!tevent_req_poll(req, ev)) {
2077                 status = map_nt_error_from_unix(errno);
2078                 goto fail;
2079         }
2080
2081         status = cli_open_recv(req, pfnum);
2082  fail:
2083         TALLOC_FREE(frame);
2084         if (!NT_STATUS_IS_OK(status)) {
2085                 cli_set_error(cli, status);
2086         }
2087         return status;
2088 }
2089
2090 /****************************************************************************
2091  Close a file.
2092 ****************************************************************************/
2093
2094 struct cli_close_state {
2095         uint16_t vwv[3];
2096 };
2097
2098 static void cli_close_done(struct tevent_req *subreq);
2099
2100 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2101                                 struct event_context *ev,
2102                                 struct cli_state *cli,
2103                                 uint16_t fnum,
2104                                 struct tevent_req **psubreq)
2105 {
2106         struct tevent_req *req, *subreq;
2107         struct cli_close_state *state;
2108
2109         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2110         if (req == NULL) {
2111                 return NULL;
2112         }
2113         SSVAL(state->vwv+0, 0, fnum);
2114         SIVALS(state->vwv+1, 0, -1);
2115
2116         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2117                                     0, NULL);
2118         if (subreq == NULL) {
2119                 TALLOC_FREE(req);
2120                 return NULL;
2121         }
2122         tevent_req_set_callback(subreq, cli_close_done, req);
2123         *psubreq = subreq;
2124         return req;
2125 }
2126
2127 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2128                                 struct event_context *ev,
2129                                 struct cli_state *cli,
2130                                 uint16_t fnum)
2131 {
2132         struct tevent_req *req, *subreq;
2133         NTSTATUS status;
2134
2135         req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2136         if (req == NULL) {
2137                 return NULL;
2138         }
2139
2140         status = cli_smb_req_send(subreq);
2141         if (!NT_STATUS_IS_OK(status)) {
2142                 tevent_req_nterror(req, status);
2143                 return tevent_req_post(req, ev);
2144         }
2145         return req;
2146 }
2147
2148 static void cli_close_done(struct tevent_req *subreq)
2149 {
2150         struct tevent_req *req = tevent_req_callback_data(
2151                 subreq, struct tevent_req);
2152         NTSTATUS status;
2153
2154         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2155         TALLOC_FREE(subreq);
2156         if (!NT_STATUS_IS_OK(status)) {
2157                 tevent_req_nterror(req, status);
2158                 return;
2159         }
2160         tevent_req_done(req);
2161 }
2162
2163 NTSTATUS cli_close_recv(struct tevent_req *req)
2164 {
2165         return tevent_req_simple_recv_ntstatus(req);
2166 }
2167
2168 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2169 {
2170         TALLOC_CTX *frame = talloc_stackframe();
2171         struct event_context *ev;
2172         struct tevent_req *req;
2173         NTSTATUS status = NT_STATUS_OK;
2174
2175         if (cli_has_async_calls(cli)) {
2176                 /*
2177                  * Can't use sync call while an async call is in flight
2178                  */
2179                 status = NT_STATUS_INVALID_PARAMETER;
2180                 goto fail;
2181         }
2182
2183         ev = event_context_init(frame);
2184         if (ev == NULL) {
2185                 status = NT_STATUS_NO_MEMORY;
2186                 goto fail;
2187         }
2188
2189         req = cli_close_send(frame, ev, cli, fnum);
2190         if (req == NULL) {
2191                 status = NT_STATUS_NO_MEMORY;
2192                 goto fail;
2193         }
2194
2195         if (!tevent_req_poll(req, ev)) {
2196                 status = map_nt_error_from_unix(errno);
2197                 goto fail;
2198         }
2199
2200         status = cli_close_recv(req);
2201  fail:
2202         TALLOC_FREE(frame);
2203         if (!NT_STATUS_IS_OK(status)) {
2204                 cli_set_error(cli, status);
2205         }
2206         return status;
2207 }
2208
2209 /****************************************************************************
2210  Truncate a file to a specified size
2211 ****************************************************************************/
2212
2213 bool cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2214 {
2215         unsigned int param_len = 6;
2216         unsigned int data_len = 8;
2217         uint16_t setup = TRANSACT2_SETFILEINFO;
2218         char param[6];
2219         unsigned char data[8];
2220         char *rparam=NULL, *rdata=NULL;
2221         int saved_timeout = cli->timeout;
2222
2223         SSVAL(param,0,fnum);
2224         SSVAL(param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2225         SSVAL(param,4,0);
2226
2227         SBVAL(data, 0, size);
2228
2229         if (!cli_send_trans(cli, SMBtrans2,
2230                             NULL,                    /* name */
2231                             -1, 0,                   /* fid, flags */
2232                             &setup, 1, 0,            /* setup, length, max */
2233                             param, param_len, 2,     /* param, length, max */
2234                             (char *)&data,  data_len,/* data, length, ... */
2235                             cli->max_xmit)) {        /* ... max */
2236                 cli->timeout = saved_timeout;
2237                 return False;
2238         }
2239
2240         if (!cli_receive_trans(cli, SMBtrans2,
2241                                 &rparam, &param_len,
2242                                 &rdata, &data_len)) {
2243                 cli->timeout = saved_timeout;
2244                 SAFE_FREE(rdata);
2245                 SAFE_FREE(rparam);
2246                 return False;
2247         }
2248
2249         cli->timeout = saved_timeout;
2250
2251         SAFE_FREE(rdata);
2252         SAFE_FREE(rparam);
2253
2254         return True;
2255 }
2256
2257
2258 /****************************************************************************
2259  send a lock with a specified locktype
2260  this is used for testing LOCKING_ANDX_CANCEL_LOCK
2261 ****************************************************************************/
2262
2263 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2264                       uint32_t offset, uint32_t len,
2265                       int timeout, unsigned char locktype)
2266 {
2267         char *p;
2268         int saved_timeout = cli->timeout;
2269
2270         memset(cli->outbuf,'\0',smb_size);
2271         memset(cli->inbuf,'\0', smb_size);
2272
2273         cli_set_message(cli->outbuf,8,0,True);
2274
2275         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2276         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2277         cli_setup_packet(cli);
2278
2279         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2280         SSVAL(cli->outbuf,smb_vwv2,fnum);
2281         SCVAL(cli->outbuf,smb_vwv3,locktype);
2282         SIVALS(cli->outbuf, smb_vwv4, timeout);
2283         SSVAL(cli->outbuf,smb_vwv6,0);
2284         SSVAL(cli->outbuf,smb_vwv7,1);
2285
2286         p = smb_buf(cli->outbuf);
2287         SSVAL(p, 0, cli->pid);
2288         SIVAL(p, 2, offset);
2289         SIVAL(p, 6, len);
2290
2291         p += 10;
2292
2293         cli_setup_bcc(cli, p);
2294
2295         cli_send_smb(cli);
2296
2297         if (timeout != 0) {
2298                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
2299         }
2300
2301         if (!cli_receive_smb(cli)) {
2302                 cli->timeout = saved_timeout;
2303                 return NT_STATUS_UNSUCCESSFUL;
2304         }
2305
2306         cli->timeout = saved_timeout;
2307
2308         return cli_nt_error(cli);
2309 }
2310
2311 /****************************************************************************
2312  Lock a file.
2313  note that timeout is in units of 2 milliseconds
2314 ****************************************************************************/
2315
2316 bool cli_lock(struct cli_state *cli, uint16_t fnum,
2317               uint32_t offset, uint32_t len, int timeout, enum brl_type lock_type)
2318 {
2319         char *p;
2320         int saved_timeout = cli->timeout;
2321
2322         memset(cli->outbuf,'\0',smb_size);
2323         memset(cli->inbuf,'\0', smb_size);
2324
2325         cli_set_message(cli->outbuf,8,0,True);
2326
2327         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2328         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2329         cli_setup_packet(cli);
2330
2331         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2332         SSVAL(cli->outbuf,smb_vwv2,fnum);
2333         SCVAL(cli->outbuf,smb_vwv3,(lock_type == READ_LOCK? 1 : 0));
2334         SIVALS(cli->outbuf, smb_vwv4, timeout);
2335         SSVAL(cli->outbuf,smb_vwv6,0);
2336         SSVAL(cli->outbuf,smb_vwv7,1);
2337
2338         p = smb_buf(cli->outbuf);
2339         SSVAL(p, 0, cli->pid);
2340         SIVAL(p, 2, offset);
2341         SIVAL(p, 6, len);
2342
2343         p += 10;
2344
2345         cli_setup_bcc(cli, p);
2346
2347         cli_send_smb(cli);
2348
2349         if (timeout != 0) {
2350                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout*2 + 5*1000);
2351         }
2352
2353         if (!cli_receive_smb(cli)) {
2354                 cli->timeout = saved_timeout;
2355                 return False;
2356         }
2357
2358         cli->timeout = saved_timeout;
2359
2360         if (cli_is_error(cli)) {
2361                 return False;
2362         }
2363
2364         return True;
2365 }
2366
2367 /****************************************************************************
2368  Unlock a file.
2369 ****************************************************************************/
2370
2371 bool cli_unlock(struct cli_state *cli, uint16_t fnum, uint32_t offset, uint32_t len)
2372 {
2373         char *p;
2374
2375         memset(cli->outbuf,'\0',smb_size);
2376         memset(cli->inbuf,'\0',smb_size);
2377
2378         cli_set_message(cli->outbuf,8,0,True);
2379
2380         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2381         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2382         cli_setup_packet(cli);
2383
2384         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2385         SSVAL(cli->outbuf,smb_vwv2,fnum);
2386         SCVAL(cli->outbuf,smb_vwv3,0);
2387         SIVALS(cli->outbuf, smb_vwv4, 0);
2388         SSVAL(cli->outbuf,smb_vwv6,1);
2389         SSVAL(cli->outbuf,smb_vwv7,0);
2390
2391         p = smb_buf(cli->outbuf);
2392         SSVAL(p, 0, cli->pid);
2393         SIVAL(p, 2, offset);
2394         SIVAL(p, 6, len);
2395         p += 10;
2396         cli_setup_bcc(cli, p);
2397         cli_send_smb(cli);
2398         if (!cli_receive_smb(cli)) {
2399                 return False;
2400         }
2401
2402         if (cli_is_error(cli)) {
2403                 return False;
2404         }
2405
2406         return True;
2407 }
2408
2409 /****************************************************************************
2410  Lock a file with 64 bit offsets.
2411 ****************************************************************************/
2412
2413 bool cli_lock64(struct cli_state *cli, uint16_t fnum,
2414                 uint64_t offset, uint64_t len, int timeout, enum brl_type lock_type)
2415 {
2416         char *p;
2417         int saved_timeout = cli->timeout;
2418         int ltype;
2419
2420         if (! (cli->capabilities & CAP_LARGE_FILES)) {
2421                 return cli_lock(cli, fnum, offset, len, timeout, lock_type);
2422         }
2423
2424         ltype = (lock_type == READ_LOCK? 1 : 0);
2425         ltype |= LOCKING_ANDX_LARGE_FILES;
2426
2427         memset(cli->outbuf,'\0',smb_size);
2428         memset(cli->inbuf,'\0', smb_size);
2429
2430         cli_set_message(cli->outbuf,8,0,True);
2431
2432         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2433         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2434         cli_setup_packet(cli);
2435
2436         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2437         SSVAL(cli->outbuf,smb_vwv2,fnum);
2438         SCVAL(cli->outbuf,smb_vwv3,ltype);
2439         SIVALS(cli->outbuf, smb_vwv4, timeout);
2440         SSVAL(cli->outbuf,smb_vwv6,0);
2441         SSVAL(cli->outbuf,smb_vwv7,1);
2442
2443         p = smb_buf(cli->outbuf);
2444         SIVAL(p, 0, cli->pid);
2445         SOFF_T_R(p, 4, offset);
2446         SOFF_T_R(p, 12, len);
2447         p += 20;
2448
2449         cli_setup_bcc(cli, p);
2450         cli_send_smb(cli);
2451
2452         if (timeout != 0) {
2453                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 5*1000);
2454         }
2455
2456         if (!cli_receive_smb(cli)) {
2457                 cli->timeout = saved_timeout;
2458                 return False;
2459         }
2460
2461         cli->timeout = saved_timeout;
2462
2463         if (cli_is_error(cli)) {
2464                 return False;
2465         }
2466
2467         return True;
2468 }
2469
2470 /****************************************************************************
2471  Unlock a file with 64 bit offsets.
2472 ****************************************************************************/
2473
2474 bool cli_unlock64(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
2475 {
2476         char *p;
2477
2478         if (! (cli->capabilities & CAP_LARGE_FILES)) {
2479                 return cli_unlock(cli, fnum, offset, len);
2480         }
2481
2482         memset(cli->outbuf,'\0',smb_size);
2483         memset(cli->inbuf,'\0',smb_size);
2484
2485         cli_set_message(cli->outbuf,8,0,True);
2486
2487         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2488         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2489         cli_setup_packet(cli);
2490
2491         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2492         SSVAL(cli->outbuf,smb_vwv2,fnum);
2493         SCVAL(cli->outbuf,smb_vwv3,LOCKING_ANDX_LARGE_FILES);
2494         SIVALS(cli->outbuf, smb_vwv4, 0);
2495         SSVAL(cli->outbuf,smb_vwv6,1);
2496         SSVAL(cli->outbuf,smb_vwv7,0);
2497
2498         p = smb_buf(cli->outbuf);
2499         SIVAL(p, 0, cli->pid);
2500         SOFF_T_R(p, 4, offset);
2501         SOFF_T_R(p, 12, len);
2502         p += 20;
2503         cli_setup_bcc(cli, p);
2504         cli_send_smb(cli);
2505         if (!cli_receive_smb(cli)) {
2506                 return False;
2507         }
2508
2509         if (cli_is_error(cli)) {
2510                 return False;
2511         }
2512
2513         return True;
2514 }
2515
2516 /****************************************************************************
2517  Get/unlock a POSIX lock on a file - internal function.
2518 ****************************************************************************/
2519
2520 static bool cli_posix_lock_internal(struct cli_state *cli, uint16_t fnum,
2521                 uint64_t offset, uint64_t len, bool wait_lock, enum brl_type lock_type)
2522 {
2523         unsigned int param_len = 4;
2524         unsigned int data_len = POSIX_LOCK_DATA_SIZE;
2525         uint16_t setup = TRANSACT2_SETFILEINFO;
2526         char param[4];
2527         unsigned char data[POSIX_LOCK_DATA_SIZE];
2528         char *rparam=NULL, *rdata=NULL;
2529         int saved_timeout = cli->timeout;
2530
2531         SSVAL(param,0,fnum);
2532         SSVAL(param,2,SMB_SET_POSIX_LOCK);
2533
2534         switch (lock_type) {
2535                 case READ_LOCK:
2536                         SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_READ);
2537                         break;
2538                 case WRITE_LOCK:
2539                         SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_WRITE);
2540                         break;
2541                 case UNLOCK_LOCK:
2542                         SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
2543                         break;
2544                 default:
2545                         return False;
2546         }
2547
2548         if (wait_lock) {
2549                 SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_WAIT);
2550                 cli->timeout = 0x7FFFFFFF;
2551         } else {
2552                 SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_NOWAIT);
2553         }
2554
2555         SIVAL(data, POSIX_LOCK_PID_OFFSET, cli->pid);
2556         SOFF_T(data, POSIX_LOCK_START_OFFSET, offset);
2557         SOFF_T(data, POSIX_LOCK_LEN_OFFSET, len);
2558
2559         if (!cli_send_trans(cli, SMBtrans2,
2560                         NULL,                        /* name */
2561                         -1, 0,                          /* fid, flags */
2562                         &setup, 1, 0,                   /* setup, length, max */
2563                         param, param_len, 2,            /* param, length, max */
2564                         (char *)&data,  data_len, cli->max_xmit /* data, length, max */
2565                         )) {
2566                 cli->timeout = saved_timeout;
2567                 return False;
2568         }
2569
2570         if (!cli_receive_trans(cli, SMBtrans2,
2571                                 &rparam, &param_len,
2572                                 &rdata, &data_len)) {
2573                 cli->timeout = saved_timeout;
2574                 SAFE_FREE(rdata);
2575                 SAFE_FREE(rparam);
2576                 return False;
2577         }
2578
2579         cli->timeout = saved_timeout;
2580
2581         SAFE_FREE(rdata);
2582         SAFE_FREE(rparam);
2583
2584         return True;
2585 }
2586
2587 /****************************************************************************
2588  POSIX Lock a file.
2589 ****************************************************************************/
2590
2591 bool cli_posix_lock(struct cli_state *cli, uint16_t fnum,
2592                         uint64_t offset, uint64_t len,
2593                         bool wait_lock, enum brl_type lock_type)
2594 {
2595         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
2596                 return False;
2597         }
2598         return cli_posix_lock_internal(cli, fnum, offset, len, wait_lock, lock_type);
2599 }
2600
2601 /****************************************************************************
2602  POSIX Unlock a file.
2603 ****************************************************************************/
2604
2605 bool cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
2606 {
2607         return cli_posix_lock_internal(cli, fnum, offset, len, False, UNLOCK_LOCK);
2608 }
2609
2610 /****************************************************************************
2611  POSIX Get any lock covering a file.
2612 ****************************************************************************/
2613
2614 bool cli_posix_getlock(struct cli_state *cli, uint16_t fnum, uint64_t *poffset, uint64_t *plen)
2615 {
2616         return True;
2617 }
2618
2619 /****************************************************************************
2620  Do a SMBgetattrE call.
2621 ****************************************************************************/
2622
2623 static void cli_getattrE_done(struct tevent_req *subreq);
2624
2625 struct cli_getattrE_state {
2626         uint16_t vwv[1];
2627         int zone_offset;
2628         uint16_t attr;
2629         SMB_OFF_T size;
2630         time_t change_time;
2631         time_t access_time;
2632         time_t write_time;
2633 };
2634
2635 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
2636                                 struct event_context *ev,
2637                                 struct cli_state *cli,
2638                                 uint16_t fnum)
2639 {
2640         struct tevent_req *req = NULL, *subreq = NULL;
2641         struct cli_getattrE_state *state = NULL;
2642         uint8_t additional_flags = 0;
2643
2644         req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
2645         if (req == NULL) {
2646                 return NULL;
2647         }
2648
2649         state->zone_offset = cli->serverzone;
2650         SSVAL(state->vwv+0,0,fnum);
2651
2652         subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
2653                               1, state->vwv, 0, NULL);
2654         if (tevent_req_nomem(subreq, req)) {
2655                 return tevent_req_post(req, ev);
2656         }
2657         tevent_req_set_callback(subreq, cli_getattrE_done, req);
2658         return req;
2659 }
2660
2661 static void cli_getattrE_done(struct tevent_req *subreq)
2662 {
2663         struct tevent_req *req = tevent_req_callback_data(
2664                 subreq, struct tevent_req);
2665         struct cli_getattrE_state *state = tevent_req_data(
2666                 req, struct cli_getattrE_state);
2667         uint8_t wct;
2668         uint16_t *vwv = NULL;
2669         NTSTATUS status;
2670
2671         status = cli_smb_recv(subreq, 11, &wct, &vwv, NULL, NULL);
2672         if (!NT_STATUS_IS_OK(status)) {
2673                 tevent_req_nterror(req, status);
2674                 return;
2675         }
2676
2677         state->size = (SMB_OFF_T)IVAL(vwv+6,0);
2678         state->attr = SVAL(vwv+10,0);
2679         state->change_time = make_unix_date2(vwv+0, state->zone_offset);
2680         state->access_time = make_unix_date2(vwv+2, state->zone_offset);
2681         state->write_time = make_unix_date2(vwv+4, state->zone_offset);
2682
2683         TALLOC_FREE(subreq);
2684         tevent_req_done(req);
2685 }
2686
2687 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
2688                         uint16_t *attr,
2689                         SMB_OFF_T *size,
2690                         time_t *change_time,
2691                         time_t *access_time,
2692                         time_t *write_time)
2693 {
2694         struct cli_getattrE_state *state = tevent_req_data(
2695                                 req, struct cli_getattrE_state);
2696         NTSTATUS status;
2697
2698         if (tevent_req_is_nterror(req, &status)) {
2699                 return status;
2700         }
2701         if (attr) {
2702                 *attr = state->attr;
2703         }
2704         if (size) {
2705                 *size = state->size;
2706         }
2707         if (change_time) {
2708                 *change_time = state->change_time;
2709         }
2710         if (access_time) {
2711                 *access_time = state->access_time;
2712         }
2713         if (write_time) {
2714                 *write_time = state->write_time;
2715         }
2716         return NT_STATUS_OK;
2717 }
2718
2719 NTSTATUS cli_getattrE(struct cli_state *cli,
2720                         uint16_t fnum,
2721                         uint16_t *attr,
2722                         SMB_OFF_T *size,
2723                         time_t *change_time,
2724                         time_t *access_time,
2725                         time_t *write_time)
2726 {
2727         TALLOC_CTX *frame = talloc_stackframe();
2728         struct event_context *ev = NULL;
2729         struct tevent_req *req = NULL;
2730         NTSTATUS status = NT_STATUS_OK;
2731
2732         if (cli_has_async_calls(cli)) {
2733                 /*
2734                  * Can't use sync call while an async call is in flight
2735                  */
2736                 status = NT_STATUS_INVALID_PARAMETER;
2737                 goto fail;
2738         }
2739
2740         ev = event_context_init(frame);
2741         if (ev == NULL) {
2742                 status = NT_STATUS_NO_MEMORY;
2743                 goto fail;
2744         }
2745
2746         req = cli_getattrE_send(frame, ev, cli, fnum);
2747         if (req == NULL) {
2748                 status = NT_STATUS_NO_MEMORY;
2749                 goto fail;
2750         }
2751
2752         if (!tevent_req_poll(req, ev)) {
2753                 status = map_nt_error_from_unix(errno);
2754                 goto fail;
2755         }
2756
2757         status = cli_getattrE_recv(req,
2758                                         attr,
2759                                         size,
2760                                         change_time,
2761                                         access_time,
2762                                         write_time);
2763
2764  fail:
2765         TALLOC_FREE(frame);
2766         if (!NT_STATUS_IS_OK(status)) {
2767                 cli_set_error(cli, status);
2768         }
2769         return status;
2770 }
2771
2772 /****************************************************************************
2773  Do a SMBgetatr call
2774 ****************************************************************************/
2775
2776 static void cli_getatr_done(struct tevent_req *subreq);
2777
2778 struct cli_getatr_state {
2779         int zone_offset;
2780         uint16_t attr;
2781         SMB_OFF_T size;
2782         time_t write_time;
2783 };
2784
2785 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
2786                                 struct event_context *ev,
2787                                 struct cli_state *cli,
2788                                 const char *fname)
2789 {
2790         struct tevent_req *req = NULL, *subreq = NULL;
2791         struct cli_getatr_state *state = NULL;
2792         uint8_t additional_flags = 0;
2793         uint8_t *bytes = NULL;
2794
2795         req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
2796         if (req == NULL) {
2797                 return NULL;
2798         }
2799
2800         state->zone_offset = cli->serverzone;
2801
2802         bytes = talloc_array(state, uint8_t, 1);
2803         if (tevent_req_nomem(bytes, req)) {
2804                 return tevent_req_post(req, ev);
2805         }
2806         bytes[0] = 4;
2807         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
2808                                    strlen(fname)+1, NULL);
2809
2810         if (tevent_req_nomem(bytes, req)) {
2811                 return tevent_req_post(req, ev);
2812         }
2813
2814         subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
2815                               0, NULL, talloc_get_size(bytes), bytes);
2816         if (tevent_req_nomem(subreq, req)) {
2817                 return tevent_req_post(req, ev);
2818         }
2819         tevent_req_set_callback(subreq, cli_getatr_done, req);
2820         return req;
2821 }
2822
2823 static void cli_getatr_done(struct tevent_req *subreq)
2824 {
2825         struct tevent_req *req = tevent_req_callback_data(
2826                 subreq, struct tevent_req);
2827         struct cli_getatr_state *state = tevent_req_data(
2828                 req, struct cli_getatr_state);
2829         uint8_t wct;
2830         uint16_t *vwv = NULL;
2831         NTSTATUS status;
2832
2833         status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL);
2834         if (!NT_STATUS_IS_OK(status)) {
2835                 tevent_req_nterror(req, status);
2836                 return;
2837         }
2838
2839         state->attr = SVAL(vwv+0,0);
2840         state->size = (SMB_OFF_T)IVAL(vwv+3,0);
2841         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
2842
2843         TALLOC_FREE(subreq);
2844         tevent_req_done(req);
2845 }
2846
2847 NTSTATUS cli_getatr_recv(struct tevent_req *req,
2848                         uint16_t *attr,
2849                         SMB_OFF_T *size,
2850                         time_t *write_time)
2851 {
2852         struct cli_getatr_state *state = tevent_req_data(
2853                                 req, struct cli_getatr_state);
2854         NTSTATUS status;
2855
2856         if (tevent_req_is_nterror(req, &status)) {
2857                 return status;
2858         }
2859         if (attr) {
2860                 *attr = state->attr;
2861         }
2862         if (size) {
2863                 *size = state->size;
2864         }
2865         if (write_time) {
2866                 *write_time = state->write_time;
2867         }
2868         return NT_STATUS_OK;
2869 }
2870
2871 NTSTATUS cli_getatr(struct cli_state *cli,
2872                         const char *fname,
2873                         uint16_t *attr,
2874                         SMB_OFF_T *size,
2875                         time_t *write_time)
2876 {
2877         TALLOC_CTX *frame = talloc_stackframe();
2878         struct event_context *ev = NULL;
2879         struct tevent_req *req = NULL;
2880         NTSTATUS status = NT_STATUS_OK;
2881
2882         if (cli_has_async_calls(cli)) {
2883                 /*
2884                  * Can't use sync call while an async call is in flight
2885                  */
2886                 status = NT_STATUS_INVALID_PARAMETER;
2887                 goto fail;
2888         }
2889
2890         ev = event_context_init(frame);
2891         if (ev == NULL) {
2892                 status = NT_STATUS_NO_MEMORY;
2893                 goto fail;
2894         }
2895
2896         req = cli_getatr_send(frame, ev, cli, fname);
2897         if (req == NULL) {
2898                 status = NT_STATUS_NO_MEMORY;
2899                 goto fail;
2900         }
2901
2902         if (!tevent_req_poll(req, ev)) {
2903                 status = map_nt_error_from_unix(errno);
2904                 goto fail;
2905         }
2906
2907         status = cli_getatr_recv(req,
2908                                 attr,
2909                                 size,
2910                                 write_time);
2911
2912  fail:
2913         TALLOC_FREE(frame);
2914         if (!NT_STATUS_IS_OK(status)) {
2915                 cli_set_error(cli, status);
2916         }
2917         return status;
2918 }
2919
2920 /****************************************************************************
2921  Do a SMBsetattrE call.
2922 ****************************************************************************/
2923
2924 static void cli_setattrE_done(struct tevent_req *subreq);
2925
2926 struct cli_setattrE_state {
2927         int dummy;
2928 };
2929
2930 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
2931                                 struct event_context *ev,
2932                                 struct cli_state *cli,
2933                                 uint16_t fnum,
2934                                 time_t change_time,
2935                                 time_t access_time,
2936                                 time_t write_time)
2937 {
2938         struct tevent_req *req = NULL, *subreq = NULL;
2939         struct cli_setattrE_state *state = NULL;
2940         uint8_t additional_flags = 0;
2941         uint16_t vwv[7];
2942
2943         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
2944         if (req == NULL) {
2945                 return NULL;
2946         }
2947
2948         memset(vwv, '\0', sizeof(vwv));
2949         SSVAL(vwv+0, 0, fnum);
2950         cli_put_dos_date2(cli, (char *)&vwv[1], 0, change_time);
2951         cli_put_dos_date2(cli, (char *)&vwv[3], 0, access_time);
2952         cli_put_dos_date2(cli, (char *)&vwv[5], 0, write_time);
2953
2954         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
2955                               7, vwv, 0, NULL);
2956         if (tevent_req_nomem(subreq, req)) {
2957                 return tevent_req_post(req, ev);
2958         }
2959         tevent_req_set_callback(subreq, cli_setattrE_done, req);
2960         return req;
2961 }
2962
2963 static void cli_setattrE_done(struct tevent_req *subreq)
2964 {
2965         struct tevent_req *req = tevent_req_callback_data(
2966                 subreq, struct tevent_req);
2967         NTSTATUS status;
2968
2969         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2970         TALLOC_FREE(subreq);
2971         if (!NT_STATUS_IS_OK(status)) {
2972                 tevent_req_nterror(req, status);
2973                 return;
2974         }
2975         tevent_req_done(req);
2976 }
2977
2978 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
2979 {
2980         return tevent_req_simple_recv_ntstatus(req);
2981 }
2982
2983 NTSTATUS cli_setattrE(struct cli_state *cli,
2984                         uint16_t fnum,
2985                         time_t change_time,
2986                         time_t access_time,
2987                         time_t write_time)
2988 {
2989         TALLOC_CTX *frame = talloc_stackframe();
2990         struct event_context *ev = NULL;
2991         struct tevent_req *req = NULL;
2992         NTSTATUS status = NT_STATUS_OK;
2993
2994         if (cli_has_async_calls(cli)) {
2995                 /*
2996                  * Can't use sync call while an async call is in flight
2997                  */
2998                 status = NT_STATUS_INVALID_PARAMETER;
2999                 goto fail;
3000         }
3001
3002         ev = event_context_init(frame);
3003         if (ev == NULL) {
3004                 status = NT_STATUS_NO_MEMORY;
3005                 goto fail;
3006         }
3007
3008         req = cli_setattrE_send(frame, ev,
3009                         cli,
3010                         fnum,
3011                         change_time,
3012                         access_time,
3013                         write_time);
3014
3015         if (req == NULL) {
3016                 status = NT_STATUS_NO_MEMORY;
3017                 goto fail;
3018         }
3019
3020         if (!tevent_req_poll(req, ev)) {
3021                 status = map_nt_error_from_unix(errno);
3022                 goto fail;
3023         }
3024
3025         status = cli_setattrE_recv(req);
3026
3027  fail:
3028         TALLOC_FREE(frame);
3029         if (!NT_STATUS_IS_OK(status)) {
3030                 cli_set_error(cli, status);
3031         }
3032         return status;
3033 }
3034
3035 /****************************************************************************
3036  Do a SMBsetatr call.
3037 ****************************************************************************/
3038
3039 static void cli_setatr_done(struct tevent_req *subreq);
3040
3041 struct cli_setatr_state {
3042         uint16_t vwv[8];
3043 };
3044
3045 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3046                                 struct event_context *ev,
3047                                 struct cli_state *cli,
3048                                 const char *fname,
3049                                 uint16_t attr,
3050                                 time_t mtime)
3051 {
3052         struct tevent_req *req = NULL, *subreq = NULL;
3053         struct cli_setatr_state *state = NULL;
3054         uint8_t additional_flags = 0;
3055         uint8_t *bytes = NULL;
3056
3057         req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3058         if (req == NULL) {
3059                 return NULL;
3060         }
3061
3062         memset(state->vwv, '\0', sizeof(state->vwv));
3063         SSVAL(state->vwv+0, 0, attr);
3064         cli_put_dos_date3(cli, (char *)&state->vwv[1], 0, mtime);
3065
3066         bytes = talloc_array(state, uint8_t, 1);
3067         if (tevent_req_nomem(bytes, req)) {
3068                 return tevent_req_post(req, ev);
3069         }
3070         bytes[0] = 4;
3071         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3072                                    strlen(fname)+1, NULL);
3073         if (tevent_req_nomem(bytes, req)) {
3074                 return tevent_req_post(req, ev);
3075         }
3076         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
3077                         talloc_get_size(bytes)+1);
3078         if (tevent_req_nomem(bytes, req)) {
3079                 return tevent_req_post(req, ev);
3080         }
3081
3082         bytes[talloc_get_size(bytes)-1] = 4;
3083         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",
3084                                    1, NULL);
3085         if (tevent_req_nomem(bytes, req)) {
3086                 return tevent_req_post(req, ev);
3087         }
3088
3089         subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3090                               8, state->vwv, talloc_get_size(bytes), bytes);
3091         if (tevent_req_nomem(subreq, req)) {
3092                 return tevent_req_post(req, ev);
3093         }
3094         tevent_req_set_callback(subreq, cli_setatr_done, req);
3095         return req;
3096 }
3097
3098 static void cli_setatr_done(struct tevent_req *subreq)
3099 {
3100         struct tevent_req *req = tevent_req_callback_data(
3101                 subreq, struct tevent_req);
3102         NTSTATUS status;
3103
3104         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
3105         TALLOC_FREE(subreq);
3106         if (!NT_STATUS_IS_OK(status)) {
3107                 tevent_req_nterror(req, status);
3108                 return;
3109         }
3110         tevent_req_done(req);
3111 }
3112
3113 NTSTATUS cli_setatr_recv(struct tevent_req *req)
3114 {
3115         return tevent_req_simple_recv_ntstatus(req);
3116 }
3117
3118 NTSTATUS cli_setatr(struct cli_state *cli,
3119                 const char *fname,
3120                 uint16_t attr,
3121                 time_t mtime)
3122 {
3123         TALLOC_CTX *frame = talloc_stackframe();
3124         struct event_context *ev = NULL;
3125         struct tevent_req *req = NULL;
3126         NTSTATUS status = NT_STATUS_OK;
3127
3128         if (cli_has_async_calls(cli)) {
3129                 /*
3130                  * Can't use sync call while an async call is in flight
3131                  */
3132                 status = NT_STATUS_INVALID_PARAMETER;
3133                 goto fail;
3134         }
3135
3136         ev = event_context_init(frame);
3137         if (ev == NULL) {
3138                 status = NT_STATUS_NO_MEMORY;
3139                 goto fail;
3140         }
3141
3142         req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
3143         if (req == NULL) {
3144                 status = NT_STATUS_NO_MEMORY;
3145                 goto fail;
3146         }
3147
3148         if (!tevent_req_poll(req, ev)) {
3149                 status = map_nt_error_from_unix(errno);
3150                 goto fail;
3151         }
3152
3153         status = cli_setatr_recv(req);
3154
3155  fail:
3156         TALLOC_FREE(frame);
3157         if (!NT_STATUS_IS_OK(status)) {
3158                 cli_set_error(cli, status);
3159         }
3160         return status;
3161 }
3162
3163 /****************************************************************************
3164  Check for existance of a dir.
3165 ****************************************************************************/
3166
3167 static void cli_chkpath_done(struct tevent_req *subreq);
3168
3169 struct cli_chkpath_state {
3170         int dummy;
3171 };
3172
3173 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
3174                                   struct event_context *ev,
3175                                   struct cli_state *cli,
3176                                   const char *fname)
3177 {
3178         struct tevent_req *req = NULL, *subreq = NULL;
3179         struct cli_chkpath_state *state = NULL;
3180         uint8_t additional_flags = 0;
3181         uint8_t *bytes = NULL;
3182
3183         req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
3184         if (req == NULL) {
3185                 return NULL;
3186         }
3187
3188         bytes = talloc_array(state, uint8_t, 1);
3189         if (tevent_req_nomem(bytes, req)) {
3190                 return tevent_req_post(req, ev);
3191         }
3192         bytes[0] = 4;
3193         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3194                                    strlen(fname)+1, NULL);
3195
3196         if (tevent_req_nomem(bytes, req)) {
3197                 return tevent_req_post(req, ev);
3198         }
3199
3200         subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
3201                               0, NULL, talloc_get_size(bytes), bytes);
3202         if (tevent_req_nomem(subreq, req)) {
3203                 return tevent_req_post(req, ev);
3204         }
3205         tevent_req_set_callback(subreq, cli_chkpath_done, req);
3206         return req;
3207 }
3208
3209 static void cli_chkpath_done(struct tevent_req *subreq)
3210 {
3211         struct tevent_req *req = tevent_req_callback_data(
3212                 subreq, struct tevent_req);
3213         NTSTATUS status;
3214
3215         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
3216         TALLOC_FREE(subreq);
3217         if (!NT_STATUS_IS_OK(status)) {
3218                 tevent_req_nterror(req, status);
3219                 return;
3220         }
3221         tevent_req_done(req);
3222 }
3223
3224 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
3225 {
3226         return tevent_req_simple_recv_ntstatus(req);
3227 }
3228
3229 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
3230 {
3231         TALLOC_CTX *frame = talloc_stackframe();
3232         struct event_context *ev = NULL;
3233         struct tevent_req *req = NULL;
3234         char *path2 = NULL;
3235         NTSTATUS status = NT_STATUS_OK;
3236
3237         if (cli_has_async_calls(cli)) {
3238                 /*
3239                  * Can't use sync call while an async call is in flight
3240                  */
3241                 status = NT_STATUS_INVALID_PARAMETER;
3242                 goto fail;
3243         }
3244
3245         path2 = talloc_strdup(frame, path);
3246         if (!path2) {
3247                 status = NT_STATUS_NO_MEMORY;
3248                 goto fail;
3249         }
3250         trim_char(path2,'\0','\\');
3251         if (!*path2) {
3252                 path2 = talloc_strdup(frame, "\\");
3253                 if (!path2) {
3254                         status = NT_STATUS_NO_MEMORY;
3255                         goto fail;
3256                 }
3257         }
3258
3259         ev = event_context_init(frame);
3260         if (ev == NULL) {
3261                 status = NT_STATUS_NO_MEMORY;
3262                 goto fail;
3263         }
3264
3265         req = cli_chkpath_send(frame, ev, cli, path2);
3266         if (req == NULL) {
3267                 status = NT_STATUS_NO_MEMORY;
3268                 goto fail;
3269         }
3270
3271         if (!tevent_req_poll(req, ev)) {
3272                 status = map_nt_error_from_unix(errno);
3273                 goto fail;
3274         }
3275
3276         status = cli_chkpath_recv(req);
3277
3278  fail:
3279         TALLOC_FREE(frame);
3280         if (!NT_STATUS_IS_OK(status)) {
3281                 cli_set_error(cli, status);
3282         }
3283         return status;
3284 }
3285
3286 /****************************************************************************
3287  Query disk space.
3288 ****************************************************************************/
3289
3290 static void cli_dskattr_done(struct tevent_req *subreq);
3291
3292 struct cli_dskattr_state {
3293         int bsize;
3294         int total;
3295         int avail;
3296 };
3297
3298 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
3299                                   struct event_context *ev,
3300                                   struct cli_state *cli)
3301 {
3302         struct tevent_req *req = NULL, *subreq = NULL;
3303         struct cli_dskattr_state *state = NULL;
3304         uint8_t additional_flags = 0;
3305
3306         req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
3307         if (req == NULL) {
3308                 return NULL;
3309         }
3310
3311         subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
3312                               0, NULL, 0, NULL);
3313         if (tevent_req_nomem(subreq, req)) {
3314                 return tevent_req_post(req, ev);
3315         }
3316         tevent_req_set_callback(subreq, cli_dskattr_done, req);
3317         return req;
3318 }
3319
3320 static void cli_dskattr_done(struct tevent_req *subreq)
3321 {
3322         struct tevent_req *req = tevent_req_callback_data(
3323                 subreq, struct tevent_req);
3324         struct cli_dskattr_state *state = tevent_req_data(
3325                 req, struct cli_dskattr_state);
3326         uint8_t wct;
3327         uint16_t *vwv = NULL;
3328         NTSTATUS status;
3329
3330         status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL);
3331         if (!NT_STATUS_IS_OK(status)) {
3332                 tevent_req_nterror(req, status);
3333                 return;
3334         }
3335         state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
3336         state->total = SVAL(vwv+0, 0);
3337         state->avail = SVAL(vwv+3, 0);
3338         TALLOC_FREE(subreq);
3339         tevent_req_done(req);
3340 }
3341
3342 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
3343 {
3344         struct cli_dskattr_state *state = tevent_req_data(
3345                                 req, struct cli_dskattr_state);
3346         NTSTATUS status;
3347
3348         if (tevent_req_is_nterror(req, &status)) {
3349                 return status;
3350         }
3351         *bsize = state->bsize;
3352         *total = state->total;
3353         *avail = state->avail;
3354         return NT_STATUS_OK;
3355 }
3356
3357 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3358 {
3359         TALLOC_CTX *frame = talloc_stackframe();
3360         struct event_context *ev = NULL;
3361         struct tevent_req *req = NULL;
3362         NTSTATUS status = NT_STATUS_OK;
3363
3364         if (cli_has_async_calls(cli)) {
3365                 /*
3366                  * Can't use sync call while an async call is in flight
3367                  */
3368                 status = NT_STATUS_INVALID_PARAMETER;
3369                 goto fail;
3370         }
3371
3372         ev = event_context_init(frame);
3373         if (ev == NULL) {
3374                 status = NT_STATUS_NO_MEMORY;
3375                 goto fail;
3376         }
3377
3378         req = cli_dskattr_send(frame, ev, cli);
3379         if (req == NULL) {
3380                 status = NT_STATUS_NO_MEMORY;
3381                 goto fail;
3382         }
3383
3384         if (!tevent_req_poll(req, ev)) {
3385                 status = map_nt_error_from_unix(errno);
3386                 goto fail;
3387         }
3388
3389         status = cli_dskattr_recv(req, bsize, total, avail);
3390
3391  fail:
3392         TALLOC_FREE(frame);
3393         if (!NT_STATUS_IS_OK(status)) {
3394                 cli_set_error(cli, status);
3395         }
3396         return status;
3397 }
3398
3399 /****************************************************************************
3400  Create and open a temporary file.
3401 ****************************************************************************/
3402
3403 int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
3404 {
3405         int len;
3406         char *p;
3407
3408         memset(cli->outbuf,'\0',smb_size);
3409         memset(cli->inbuf,'\0',smb_size);
3410
3411         cli_set_message(cli->outbuf,3,0,True);
3412
3413         SCVAL(cli->outbuf,smb_com,SMBctemp);
3414         SSVAL(cli->outbuf,smb_tid,cli->cnum);
3415         cli_setup_packet(cli);
3416
3417         SSVAL(cli->outbuf,smb_vwv0,0);
3418         SIVALS(cli->outbuf,smb_vwv1,-1);
3419
3420         p = smb_buf(cli->outbuf);
3421         *p++ = 4;
3422         p += clistr_push(cli, p, path,
3423                         cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
3424
3425         cli_setup_bcc(cli, p);
3426
3427         cli_send_smb(cli);
3428         if (!cli_receive_smb(cli)) {
3429                 return -1;
3430         }
3431
3432         if (cli_is_error(cli)) {
3433                 return -1;
3434         }
3435
3436         /* despite the spec, the result has a -1, followed by
3437            length, followed by name */
3438         p = smb_buf(cli->inbuf);
3439         p += 4;
3440         len = smb_buflen(cli->inbuf) - 4;
3441         if (len <= 0 || len > PATH_MAX) return -1;
3442
3443         if (tmp_path) {
3444                 char *path2 = SMB_MALLOC_ARRAY(char, len+1);
3445                 if (!path2) {
3446                         return -1;
3447                 }
3448                 clistr_pull(cli->inbuf, path2, p,
3449                             len+1, len, STR_ASCII);
3450                 *tmp_path = path2;
3451         }
3452
3453         return SVAL(cli->inbuf,smb_vwv0);
3454 }
3455
3456 /*
3457    send a raw ioctl - used by the torture code
3458 */
3459 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
3460 {
3461         memset(cli->outbuf,'\0',smb_size);
3462         memset(cli->inbuf,'\0',smb_size);
3463
3464         cli_set_message(cli->outbuf, 3, 0, True);
3465         SCVAL(cli->outbuf,smb_com,SMBioctl);
3466         cli_setup_packet(cli);
3467
3468         SSVAL(cli->outbuf, smb_vwv0, fnum);
3469         SSVAL(cli->outbuf, smb_vwv1, code>>16);
3470         SSVAL(cli->outbuf, smb_vwv2, (code&0xFFFF));
3471
3472         cli_send_smb(cli);
3473         if (!cli_receive_smb(cli)) {
3474                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
3475         }
3476
3477         if (cli_is_error(cli)) {
3478                 return cli_nt_error(cli);
3479         }
3480
3481         *blob = data_blob_null;
3482
3483         return NT_STATUS_OK;
3484 }
3485
3486 /*********************************************************
3487  Set an extended attribute utility fn.
3488 *********************************************************/
3489
3490 static bool cli_set_ea(struct cli_state *cli, uint16_t setup, char *param, unsigned int param_len,
3491                         const char *ea_name, const char *ea_val, size_t ea_len)
3492 {
3493         unsigned int data_len = 0;
3494         char *data = NULL;
3495         char *rparam=NULL, *rdata=NULL;
3496         char *p;
3497         size_t ea_namelen = strlen(ea_name);
3498
3499         if (ea_namelen == 0 && ea_len == 0) {
3500                 data_len = 4;
3501                 data = (char *)SMB_MALLOC(data_len);
3502                 if (!data) {
3503                         return False;
3504                 }
3505                 p = data;
3506                 SIVAL(p,0,data_len);
3507         } else {
3508                 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
3509                 data = (char *)SMB_MALLOC(data_len);
3510                 if (!data) {
3511                         return False;
3512                 }
3513                 p = data;
3514                 SIVAL(p,0,data_len);
3515                 p += 4;
3516                 SCVAL(p, 0, 0); /* EA flags. */
3517                 SCVAL(p, 1, ea_namelen);
3518                 SSVAL(p, 2, ea_len);
3519                 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
3520                 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
3521         }
3522
3523         if (!cli_send_trans(cli, SMBtrans2,
3524                         NULL,                        /* name */
3525                         -1, 0,                          /* fid, flags */
3526                         &setup, 1, 0,                   /* setup, length, max */
3527                         param, param_len, 2,            /* param, length, max */
3528                         data,  data_len, cli->max_xmit /* data, length, max */
3529                         )) {
3530                 SAFE_FREE(data);
3531                 return False;
3532         }
3533
3534         if (!cli_receive_trans(cli, SMBtrans2,
3535                         &rparam, &param_len,
3536                         &rdata, &data_len)) {
3537                         SAFE_FREE(data);
3538                 return false;
3539         }
3540
3541         SAFE_FREE(data);
3542         SAFE_FREE(rdata);
3543         SAFE_FREE(rparam);
3544
3545         return True;
3546 }
3547
3548 /*********************************************************
3549  Set an extended attribute on a pathname.
3550 *********************************************************/
3551
3552 bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len)
3553 {
3554         uint16_t setup = TRANSACT2_SETPATHINFO;
3555         unsigned int param_len = 0;
3556         char *param;
3557         size_t srclen = 2*(strlen(path)+1);
3558         char *p;
3559         bool ret;
3560
3561         param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
3562         if (!param) {
3563                 return false;
3564         }
3565         memset(param, '\0', 6);
3566         SSVAL(param,0,SMB_INFO_SET_EA);
3567         p = &param[6];
3568
3569         p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
3570         param_len = PTR_DIFF(p, param);
3571
3572         ret = cli_set_ea(cli, setup, param, param_len, ea_name, ea_val, ea_len);
3573         SAFE_FREE(param);
3574         return ret;
3575 }
3576
3577 /*********************************************************
3578  Set an extended attribute on an fnum.
3579 *********************************************************/
3580
3581 bool cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum, const char *ea_name, const char *ea_val, size_t ea_len)
3582 {
3583         char param[6];
3584         uint16_t setup = TRANSACT2_SETFILEINFO;
3585
3586         memset(param, 0, 6);
3587         SSVAL(param,0,fnum);
3588         SSVAL(param,2,SMB_INFO_SET_EA);
3589
3590         return cli_set_ea(cli, setup, param, 6, ea_name, ea_val, ea_len);
3591 }
3592
3593 /*********************************************************
3594  Get an extended attribute list utility fn.
3595 *********************************************************/
3596
3597 static bool cli_get_ea_list(struct cli_state *cli,
3598                 uint16_t setup, char *param, unsigned int param_len,
3599                 TALLOC_CTX *ctx,
3600                 size_t *pnum_eas,
3601                 struct ea_struct **pea_list)
3602 {
3603         unsigned int data_len = 0;
3604         unsigned int rparam_len, rdata_len;
3605         char *rparam=NULL, *rdata=NULL;
3606         char *p;
3607         size_t ea_size;
3608         size_t num_eas;
3609         bool ret = False;
3610         struct ea_struct *ea_list;
3611
3612         *pnum_eas = 0;
3613         if (pea_list) {
3614                 *pea_list = NULL;
3615         }
3616
3617         if (!cli_send_trans(cli, SMBtrans2,
3618                         NULL,           /* Name */
3619                         -1, 0,          /* fid, flags */
3620                         &setup, 1, 0,   /* setup, length, max */
3621                         param, param_len, 10, /* param, length, max */
3622                         NULL, data_len, cli->max_xmit /* data, length, max */
3623                                 )) {
3624                 return False;
3625         }
3626
3627         if (!cli_receive_trans(cli, SMBtrans2,
3628                         &rparam, &rparam_len,
3629                         &rdata, &rdata_len)) {
3630                 return False;
3631         }
3632
3633         if (!rdata || rdata_len < 4) {
3634                 goto out;
3635         }
3636
3637         ea_size = (size_t)IVAL(rdata,0);
3638         if (ea_size > rdata_len) {
3639                 goto out;
3640         }
3641
3642         if (ea_size == 0) {
3643                 /* No EA's present. */
3644                 ret = True;
3645                 goto out;
3646         }
3647
3648         p = rdata + 4;
3649         ea_size -= 4;
3650
3651         /* Validate the EA list and count it. */
3652         for (num_eas = 0; ea_size >= 4; num_eas++) {
3653                 unsigned int ea_namelen = CVAL(p,1);
3654                 unsigned int ea_valuelen = SVAL(p,2);
3655                 if (ea_namelen == 0) {
3656                         goto out;
3657                 }
3658                 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
3659                         goto out;
3660                 }
3661                 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
3662                 p += 4 + ea_namelen + 1 + ea_valuelen;
3663         }
3664
3665         if (num_eas == 0) {
3666                 ret = True;
3667                 goto out;
3668         }
3669
3670         *pnum_eas = num_eas;
3671         if (!pea_list) {
3672                 /* Caller only wants number of EA's. */
3673                 ret = True;
3674                 goto out;
3675         }
3676
3677         ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
3678         if (!ea_list) {
3679                 goto out;
3680         }
3681
3682         ea_size = (size_t)IVAL(rdata,0);
3683         p = rdata + 4;
3684
3685         for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
3686                 struct ea_struct *ea = &ea_list[num_eas];
3687                 fstring unix_ea_name;
3688                 unsigned int ea_namelen = CVAL(p,1);
3689                 unsigned int ea_valuelen = SVAL(p,2);
3690
3691                 ea->flags = CVAL(p,0);
3692                 unix_ea_name[0] = '\0';
3693                 pull_ascii_fstring(unix_ea_name, p + 4);
3694                 ea->name = talloc_strdup(ctx, unix_ea_name);
3695                 /* Ensure the value is null terminated (in case it's a string). */
3696                 ea->value = data_blob_talloc(ctx, NULL, ea_valuelen + 1);
3697                 if (!ea->value.data) {
3698                         goto out;
3699                 }
3700                 if (ea_valuelen) {
3701                         memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
3702                 }
3703                 ea->value.data[ea_valuelen] = 0;
3704                 ea->value.length--;
3705                 p += 4 + ea_namelen + 1 + ea_valuelen;
3706         }
3707
3708         *pea_list = ea_list;
3709         ret = True;
3710
3711  out :
3712
3713         SAFE_FREE(rdata);
3714         SAFE_FREE(rparam);
3715         return ret;
3716 }
3717
3718 /*********************************************************
3719  Get an extended attribute list from a pathname.
3720 *********************************************************/
3721
3722 bool cli_get_ea_list_path(struct cli_state *cli, const char *path,
3723                 TALLOC_CTX *ctx,
3724                 size_t *pnum_eas,
3725                 struct ea_struct **pea_list)
3726 {
3727         uint16_t setup = TRANSACT2_QPATHINFO;
3728         unsigned int param_len = 0;
3729         char *param;
3730         char *p;
3731         size_t srclen = 2*(strlen(path)+1);
3732         bool ret;
3733
3734         param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
3735         if (!param) {
3736                 return false;
3737         }
3738         p = param;
3739         memset(p, 0, 6);
3740         SSVAL(p, 0, SMB_INFO_QUERY_ALL_EAS);
3741         p += 6;
3742         p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
3743         param_len = PTR_DIFF(p, param);
3744
3745         ret = cli_get_ea_list(cli, setup, param, param_len, ctx, pnum_eas, pea_list);
3746         SAFE_FREE(param);
3747         return ret;
3748 }
3749
3750 /*********************************************************
3751  Get an extended attribute list from an fnum.
3752 *********************************************************/
3753
3754 bool cli_get_ea_list_fnum(struct cli_state *cli, uint16_t fnum,
3755                 TALLOC_CTX *ctx,
3756                 size_t *pnum_eas,
3757                 struct ea_struct **pea_list)
3758 {
3759         uint16_t setup = TRANSACT2_QFILEINFO;
3760         char param[6];
3761
3762         memset(param, 0, 6);
3763         SSVAL(param,0,fnum);
3764         SSVAL(param,2,SMB_INFO_SET_EA);
3765
3766         return cli_get_ea_list(cli, setup, param, 6, ctx, pnum_eas, pea_list);
3767 }
3768
3769 /****************************************************************************
3770  Convert open "flags" arg to uint32_t on wire.
3771 ****************************************************************************/
3772
3773 static uint32_t open_flags_to_wire(int flags)
3774 {
3775         int open_mode = flags & O_ACCMODE;
3776         uint32_t ret = 0;
3777
3778         switch (open_mode) {
3779                 case O_WRONLY:
3780                         ret |= SMB_O_WRONLY;
3781                         break;
3782                 case O_RDWR:
3783                         ret |= SMB_O_RDWR;
3784                         break;
3785                 default:
3786                 case O_RDONLY:
3787                         ret |= SMB_O_RDONLY;
3788                         break;
3789         }
3790
3791         if (flags & O_CREAT) {
3792                 ret |= SMB_O_CREAT;
3793         }
3794         if (flags & O_EXCL) {
3795                 ret |= SMB_O_EXCL;
3796         }
3797         if (flags & O_TRUNC) {
3798                 ret |= SMB_O_TRUNC;
3799         }
3800 #if defined(O_SYNC)
3801         if (flags & O_SYNC) {
3802                 ret |= SMB_O_SYNC;
3803         }
3804 #endif /* O_SYNC */
3805         if (flags & O_APPEND) {
3806                 ret |= SMB_O_APPEND;
3807         }
3808 #if defined(O_DIRECT)
3809         if (flags & O_DIRECT) {
3810                 ret |= SMB_O_DIRECT;
3811         }
3812 #endif
3813 #if defined(O_DIRECTORY)
3814         if (flags & O_DIRECTORY) {
3815                 ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
3816                 ret |= SMB_O_DIRECTORY;
3817         }
3818 #endif
3819         return ret;
3820 }
3821
3822 /****************************************************************************
3823  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
3824 ****************************************************************************/
3825
3826 struct posix_open_state {
3827         uint16_t setup;
3828         uint8_t *param;
3829         uint8_t data[18];
3830         uint16_t fnum; /* Out */
3831 };
3832
3833 static void cli_posix_open_internal_done(struct tevent_req *subreq)
3834 {
3835         struct tevent_req *req = tevent_req_callback_data(
3836                                 subreq, struct tevent_req);
3837         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
3838         NTSTATUS status;
3839         uint8_t *data;
3840         uint32_t num_data;
3841
3842         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, &data, &num_data);
3843         TALLOC_FREE(subreq);
3844         if (!NT_STATUS_IS_OK(status)) {
3845                 tevent_req_nterror(req, status);
3846                 return;
3847         }
3848         if (num_data < 12) {
3849                 tevent_req_nterror(req, status);
3850                 return;
3851         }
3852         state->fnum = SVAL(data,2);
3853         tevent_req_done(req);
3854 }
3855
3856 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
3857                                         struct event_context *ev,
3858                                         struct cli_state *cli,
3859                                         const char *fname,
3860                                         int flags,
3861                                         mode_t mode,
3862                                         bool is_dir)
3863 {
3864         struct tevent_req *req = NULL, *subreq = NULL;
3865         struct posix_open_state *state = NULL;
3866         uint32_t wire_flags = open_flags_to_wire(flags);
3867
3868         req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
3869         if (req == NULL) {
3870                 return NULL;
3871         }
3872
3873         /* Setup setup word. */
3874         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
3875
3876         /* Setup param array. */
3877         state->param = talloc_array(state, uint8_t, 6);
3878         if (tevent_req_nomem(state->param, req)) {
3879                 return tevent_req_post(req, ev);
3880         }
3881         memset(state->param, '\0', 6);
3882         SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
3883
3884         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
3885                                    strlen(fname)+1, NULL);
3886
3887         if (tevent_req_nomem(state->param, req)) {
3888                 return tevent_req_post(req, ev);
3889         }
3890
3891         /* Setup data words. */
3892         if (is_dir) {
3893                 wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
3894                 wire_flags |= SMB_O_DIRECTORY;
3895         }
3896
3897         SIVAL(state->data,0,0); /* No oplock. */
3898         SIVAL(state->data,4,wire_flags);
3899         SIVAL(state->data,8,unix_perms_to_wire(mode));
3900         SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
3901         SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
3902
3903         subreq = cli_trans_send(state,                  /* mem ctx. */
3904                                 ev,                     /* event ctx. */
3905                                 cli,                    /* cli_state. */
3906                                 SMBtrans2,              /* cmd. */
3907                                 NULL,                   /* pipe name. */
3908                                 -1,                     /* fid. */
3909                                 0,                      /* function. */
3910                                 0,                      /* flags. */
3911                                 &state->setup,          /* setup. */
3912                                 1,                      /* num setup uint16_t words. */
3913                                 0,                      /* max returned setup. */
3914                                 state->param,           /* param. */
3915                                 talloc_get_size(state->param),/* num param. */
3916                                 2,                      /* max returned param. */
3917                                 state->data,            /* data. */
3918                                 18,                     /* num data. */
3919                                 12);                    /* max returned data. */
3920
3921         if (tevent_req_nomem(subreq, req)) {
3922                 return tevent_req_post(req, ev);
3923         }
3924         tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
3925         return req;
3926 }
3927
3928 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
3929                                         struct event_context *ev,
3930                                         struct cli_state *cli,
3931                                         const char *fname,
3932                                         int flags,
3933                                         mode_t mode)
3934 {
3935         return cli_posix_open_internal_send(mem_ctx, ev,
3936                                 cli, fname, flags, mode, false);
3937 }
3938
3939 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
3940 {
3941         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
3942         NTSTATUS status;
3943
3944         if (tevent_req_is_nterror(req, &status)) {
3945                 return status;
3946         }
3947         *pfnum = state->fnum;
3948         return NT_STATUS_OK;
3949 }
3950
3951 /****************************************************************************
3952  Open - POSIX semantics. Doesn't request oplock.
3953 ****************************************************************************/
3954
3955 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
3956                         int flags, mode_t mode, uint16_t *pfnum)
3957 {
3958
3959         TALLOC_CTX *frame = talloc_stackframe();
3960         struct event_context *ev = NULL;
3961         struct tevent_req *req = NULL;
3962         NTSTATUS status = NT_STATUS_OK;
3963
3964         if (cli_has_async_calls(cli)) {
3965                 /*
3966                  * Can't use sync call while an async call is in flight
3967                  */
3968                 status = NT_STATUS_INVALID_PARAMETER;
3969                 goto fail;
3970         }
3971
3972         ev = event_context_init(frame);
3973         if (ev == NULL) {
3974                 status = NT_STATUS_NO_MEMORY;
3975                 goto fail;
3976         }
3977
3978         req = cli_posix_open_send(frame,
3979                                 ev,
3980                                 cli,
3981                                 fname,
3982                                 flags,
3983                                 mode);
3984         if (req == NULL) {
3985                 status = NT_STATUS_NO_MEMORY;
3986                 goto fail;
3987         }
3988
3989         if (!tevent_req_poll(req, ev)) {
3990                 status = map_nt_error_from_unix(errno);
3991                 goto fail;
3992         }
3993
3994         status = cli_posix_open_recv(req, pfnum);
3995
3996  fail:
3997         TALLOC_FREE(frame);
3998         if (!NT_STATUS_IS_OK(status)) {
3999                 cli_set_error(cli, status);
4000         }
4001         return status;
4002 }
4003
4004 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
4005                                         struct event_context *ev,
4006                                         struct cli_state *cli,
4007                                         const char *fname,
4008                                         mode_t mode)
4009 {
4010         return cli_posix_open_internal_send(mem_ctx, ev,
4011                                 cli, fname, O_CREAT, mode, true);
4012 }
4013
4014 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
4015 {
4016         NTSTATUS status;
4017
4018         if (tevent_req_is_nterror(req, &status)) {
4019                 return status;
4020         }
4021         return NT_STATUS_OK;
4022 }
4023
4024 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
4025 {
4026         TALLOC_CTX *frame = talloc_stackframe();
4027         struct event_context *ev = NULL;
4028         struct tevent_req *req = NULL;
4029         NTSTATUS status = NT_STATUS_OK;
4030
4031         if (cli_has_async_calls(cli)) {
4032                 /*
4033                  * Can't use sync call while an async call is in flight
4034                  */
4035                 status = NT_STATUS_INVALID_PARAMETER;
4036                 goto fail;
4037         }
4038
4039         ev = event_context_init(frame);
4040         if (ev == NULL) {
4041                 status = NT_STATUS_NO_MEMORY;
4042                 goto fail;
4043         }
4044
4045         req = cli_posix_mkdir_send(frame,
4046                                 ev,
4047                                 cli,
4048                                 fname,
4049                                 mode);
4050         if (req == NULL) {
4051                 status = NT_STATUS_NO_MEMORY;
4052                 goto fail;
4053         }
4054
4055         if (!tevent_req_poll(req, ev)) {
4056                 status = map_nt_error_from_unix(errno);
4057                 goto fail;
4058         }
4059
4060         status = cli_posix_mkdir_recv(req);
4061
4062  fail:
4063         TALLOC_FREE(frame);
4064         if (!NT_STATUS_IS_OK(status)) {
4065                 cli_set_error(cli, status);
4066         }
4067         return status;
4068 }
4069
4070 /****************************************************************************
4071  unlink or rmdir - POSIX semantics.
4072 ****************************************************************************/
4073
4074 struct unlink_state {
4075         uint16_t setup;
4076         uint8_t data[2];
4077 };
4078
4079 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
4080 {
4081         struct tevent_req *req = tevent_req_callback_data(
4082                                 subreq, struct tevent_req);
4083         struct unlink_state *state = tevent_req_data(req, struct unlink_state);
4084         NTSTATUS status;
4085
4086         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, NULL, NULL);
4087         TALLOC_FREE(subreq);
4088         if (!NT_STATUS_IS_OK(status)) {
4089                 tevent_req_nterror(req, status);
4090                 return;
4091         }
4092         tevent_req_done(req);
4093 }
4094
4095 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
4096                                         struct event_context *ev,
4097                                         struct cli_state *cli,
4098                                         const char *fname,
4099                                         bool is_dir)
4100 {
4101         struct tevent_req *req = NULL, *subreq = NULL;
4102         struct unlink_state *state = NULL;
4103         uint8_t *param = NULL;
4104
4105         req = tevent_req_create(mem_ctx, &state, struct unlink_state);
4106         if (req == NULL) {
4107                 return NULL;
4108         }
4109
4110         /* Setup setup word. */
4111         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4112
4113         /* Setup param array. */
4114         param = talloc_array(state, uint8_t, 6);
4115         if (tevent_req_nomem(param, req)) {
4116                 return tevent_req_post(req, ev);
4117         }
4118         memset(param, '\0', 6);
4119         SSVAL(param, 0, SMB_POSIX_PATH_UNLINK);
4120
4121         param = trans2_bytes_push_str(param, cli_ucs2(cli), fname,
4122                                    strlen(fname)+1, NULL);
4123
4124         if (tevent_req_nomem(param, req)) {
4125                 return tevent_req_post(req, ev);
4126         }
4127
4128         /* Setup data word. */
4129         SSVAL(state->data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET :
4130                         SMB_POSIX_UNLINK_FILE_TARGET);
4131
4132         subreq = cli_trans_send(state,                  /* mem ctx. */
4133                                 ev,                     /* event ctx. */
4134                                 cli,                    /* cli_state. */
4135                                 SMBtrans2,              /* cmd. */
4136                                 NULL,                   /* pipe name. */
4137                                 -1,                     /* fid. */
4138                                 0,                      /* function. */
4139                                 0,                      /* flags. */
4140                                 &state->setup,          /* setup. */
4141                                 1,                      /* num setup uint16_t words. */
4142                                 0,                      /* max returned setup. */
4143                                 param,                  /* param. */
4144                                 talloc_get_size(param), /* num param. */
4145                                 2,                      /* max returned param. */
4146                                 state->data,            /* data. */
4147                                 2,                      /* num data. */
4148                                 0);                     /* max returned data. */
4149
4150         if (tevent_req_nomem(subreq, req)) {
4151                 return tevent_req_post(req, ev);
4152         }
4153         tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
4154         return req;
4155 }
4156
4157 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
4158                                         struct event_context *ev,
4159                                         struct cli_state *cli,
4160                                         const char *fname)
4161 {
4162         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, false);
4163 }
4164
4165 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
4166 {
4167         NTSTATUS status;
4168
4169         if (tevent_req_is_nterror(req, &status)) {
4170                 return status;
4171         }
4172         return NT_STATUS_OK;
4173 }
4174
4175 /****************************************************************************
4176  unlink - POSIX semantics.
4177 ****************************************************************************/
4178
4179 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
4180 {
4181         TALLOC_CTX *frame = talloc_stackframe();
4182         struct event_context *ev = NULL;
4183         struct tevent_req *req = NULL;
4184         NTSTATUS status = NT_STATUS_OK;
4185
4186         if (cli_has_async_calls(cli)) {
4187                 /*
4188                  * Can't use sync call while an async call is in flight
4189                  */
4190                 status = NT_STATUS_INVALID_PARAMETER;
4191                 goto fail;
4192         }
4193
4194         ev = event_context_init(frame);
4195         if (ev == NULL) {
4196                 status = NT_STATUS_NO_MEMORY;
4197                 goto fail;
4198         }
4199
4200         req = cli_posix_unlink_send(frame,
4201                                 ev,
4202                                 cli,
4203                                 fname);
4204         if (req == NULL) {
4205                 status = NT_STATUS_NO_MEMORY;
4206                 goto fail;
4207         }
4208
4209         if (!tevent_req_poll(req, ev)) {
4210                 status = map_nt_error_from_unix(errno);
4211                 goto fail;
4212         }
4213
4214         status = cli_posix_unlink_recv(req);
4215
4216  fail:
4217         TALLOC_FREE(frame);
4218         if (!NT_STATUS_IS_OK(status)) {
4219                 cli_set_error(cli, status);
4220         }
4221         return status;
4222 }
4223
4224 /****************************************************************************
4225  rmdir - POSIX semantics.
4226 ****************************************************************************/
4227
4228 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
4229                                         struct event_context *ev,
4230                                         struct cli_state *cli,
4231                                         const char *fname)
4232 {
4233         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, true);
4234 }
4235
4236 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
4237 {
4238         NTSTATUS status;
4239
4240         if (tevent_req_is_nterror(req, &status)) {
4241                 return status;
4242         }
4243         return NT_STATUS_OK;
4244 }
4245
4246 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
4247 {
4248         TALLOC_CTX *frame = talloc_stackframe();
4249         struct event_context *ev = NULL;
4250         struct tevent_req *req = NULL;
4251         NTSTATUS status = NT_STATUS_OK;
4252
4253         if (cli_has_async_calls(cli)) {
4254                 /*
4255                  * Can't use sync call while an async call is in flight
4256                  */
4257                 status = NT_STATUS_INVALID_PARAMETER;
4258                 goto fail;
4259         }
4260
4261         ev = event_context_init(frame);
4262         if (ev == NULL) {
4263                 status = NT_STATUS_NO_MEMORY;
4264                 goto fail;
4265         }
4266
4267         req = cli_posix_rmdir_send(frame,
4268                                 ev,
4269                                 cli,
4270                                 fname);
4271         if (req == NULL) {
4272                 status = NT_STATUS_NO_MEMORY;
4273                 goto fail;
4274         }
4275
4276         if (!tevent_req_poll(req, ev)) {
4277                 status = map_nt_error_from_unix(errno);
4278                 goto fail;
4279         }
4280
4281         status = cli_posix_rmdir_recv(req, frame);
4282
4283  fail:
4284         TALLOC_FREE(frame);
4285         if (!NT_STATUS_IS_OK(status)) {
4286                 cli_set_error(cli, status);
4287         }
4288         return status;
4289 }