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