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