Make cli_ftruncate async. Also add a simple test.
[ira/wip.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 /***********************************************************
24  Common function for pushing stings, used by smb_bytes_push_str()
25  and trans_bytes_push_str(). Only difference is the align_odd
26  parameter setting.
27 ***********************************************************/
28
29 static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
30                                 const char *str, size_t str_len,
31                                 bool align_odd,
32                                 size_t *pconverted_size)
33 {
34         size_t buflen;
35         char *converted;
36         size_t converted_size;
37
38         if (buf == NULL) {
39                 return NULL;
40         }
41
42         buflen = talloc_get_size(buf);
43
44         if (align_odd && ucs2 && (buflen % 2 == 0)) {
45                 /*
46                  * We're pushing into an SMB buffer, align odd
47                  */
48                 buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
49                 if (buf == NULL) {
50                         return NULL;
51                 }
52                 buf[buflen] = '\0';
53                 buflen += 1;
54         }
55
56         if (!convert_string_talloc(talloc_tos(), CH_UNIX,
57                                    ucs2 ? CH_UTF16LE : CH_DOS,
58                                    str, str_len, &converted,
59                                    &converted_size, true)) {
60                 return NULL;
61         }
62
63         buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
64                                    buflen + converted_size);
65         if (buf == NULL) {
66                 TALLOC_FREE(converted);
67                 return NULL;
68         }
69
70         memcpy(buf + buflen, converted, converted_size);
71
72         TALLOC_FREE(converted);
73
74         if (pconverted_size) {
75                 *pconverted_size = converted_size;
76         }
77
78         return buf;
79 }
80
81 /***********************************************************
82  Push a string into an SMB buffer, with odd byte alignment
83  if it's a UCS2 string.
84 ***********************************************************/
85
86 uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
87                             const char *str, size_t str_len,
88                             size_t *pconverted_size)
89 {
90         return internal_bytes_push_str(buf, ucs2, str, str_len,
91                         true, pconverted_size);
92 }
93
94 /***********************************************************
95  Same as smb_bytes_push_str(), but without the odd byte
96  align for ucs2 (we're pushing into a param or data block).
97  static for now, although this will probably change when
98  other modules use async trans calls.
99 ***********************************************************/
100
101 static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
102                             const char *str, size_t str_len,
103                             size_t *pconverted_size)
104 {
105         return internal_bytes_push_str(buf, ucs2, str, str_len,
106                         false, pconverted_size);
107 }
108
109 /****************************************************************************
110  Hard/Symlink a file (UNIX extensions).
111  Creates new name (sym)linked to oldname.
112 ****************************************************************************/
113
114 struct link_state {
115         uint16_t setup;
116         uint8_t *param;
117         uint8_t *data;
118 };
119
120 static void cli_posix_link_internal_done(struct tevent_req *subreq)
121 {
122         struct tevent_req *req = tevent_req_callback_data(
123                                 subreq, struct tevent_req);
124         struct link_state *state = tevent_req_data(req, struct link_state);
125         NTSTATUS status;
126
127         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, NULL, NULL);
128         TALLOC_FREE(subreq);
129         if (!NT_STATUS_IS_OK(status)) {
130                 tevent_req_nterror(req, status);
131                 return;
132         }
133         tevent_req_done(req);
134 }
135
136 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
137                                         struct event_context *ev,
138                                         struct cli_state *cli,
139                                         const char *oldname,
140                                         const char *newname,
141                                         bool hardlink)
142 {
143         struct tevent_req *req = NULL, *subreq = NULL;
144         struct link_state *state = NULL;
145
146         req = tevent_req_create(mem_ctx, &state, struct link_state);
147         if (req == NULL) {
148                 return NULL;
149         }
150
151         /* Setup setup word. */
152         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
153
154         /* Setup param array. */
155         state->param = talloc_array(state, uint8_t, 6);
156         if (tevent_req_nomem(state->param, req)) {
157                 return tevent_req_post(req, ev);
158         }
159         memset(state->param, '\0', 6);
160         SSVAL(state->param,0,hardlink ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
161
162         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), newname,
163                                    strlen(newname)+1, NULL);
164
165         if (tevent_req_nomem(state->param, req)) {
166                 return tevent_req_post(req, ev);
167         }
168
169         /* Setup data array. */
170         state->data = talloc_array(state, uint8_t, 0);
171         if (tevent_req_nomem(state->data, req)) {
172                 return tevent_req_post(req, ev);
173         }
174         state->data = trans2_bytes_push_str(state->data, cli_ucs2(cli), oldname,
175                                    strlen(oldname)+1, NULL);
176
177         subreq = cli_trans_send(state,                  /* mem ctx. */
178                                 ev,                     /* event ctx. */
179                                 cli,                    /* cli_state. */
180                                 SMBtrans2,              /* cmd. */
181                                 NULL,                   /* pipe name. */
182                                 -1,                     /* fid. */
183                                 0,                      /* function. */
184                                 0,                      /* flags. */
185                                 &state->setup,          /* setup. */
186                                 1,                      /* num setup uint16_t words. */
187                                 0,                      /* max returned setup. */
188                                 state->param,           /* param. */
189                                 talloc_get_size(state->param),  /* num param. */
190                                 2,                      /* max returned param. */
191                                 state->data,            /* data. */
192                                 talloc_get_size(state->data),   /* num data. */
193                                 0);                     /* max returned data. */
194
195         if (tevent_req_nomem(subreq, req)) {
196                 return tevent_req_post(req, ev);
197         }
198         tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
199         return req;
200 }
201
202 /****************************************************************************
203  Symlink a file (UNIX extensions).
204 ****************************************************************************/
205
206 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
207                                         struct event_context *ev,
208                                         struct cli_state *cli,
209                                         const char *oldname,
210                                         const char *newname)
211 {
212         return cli_posix_link_internal_send(mem_ctx, ev, cli,
213                         oldname, newname, false);
214 }
215
216 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
217 {
218         NTSTATUS status;
219
220         if (tevent_req_is_nterror(req, &status)) {
221                 return status;
222         }
223         return NT_STATUS_OK;
224 }
225
226 NTSTATUS cli_posix_symlink(struct cli_state *cli,
227                         const char *oldname,
228                         const char *newname)
229 {
230         TALLOC_CTX *frame = talloc_stackframe();
231         struct event_context *ev = NULL;
232         struct tevent_req *req = NULL;
233         NTSTATUS status = NT_STATUS_OK;
234
235         if (cli_has_async_calls(cli)) {
236                 /*
237                  * Can't use sync call while an async call is in flight
238                  */
239                 status = NT_STATUS_INVALID_PARAMETER;
240                 goto fail;
241         }
242
243         ev = event_context_init(frame);
244         if (ev == NULL) {
245                 status = NT_STATUS_NO_MEMORY;
246                 goto fail;
247         }
248
249         req = cli_posix_symlink_send(frame,
250                                 ev,
251                                 cli,
252                                 oldname,
253                                 newname);
254         if (req == NULL) {
255                 status = NT_STATUS_NO_MEMORY;
256                 goto fail;
257         }
258
259         if (!tevent_req_poll(req, ev)) {
260                 status = map_nt_error_from_unix(errno);
261                 goto fail;
262         }
263
264         status = cli_posix_symlink_recv(req);
265
266  fail:
267         TALLOC_FREE(frame);
268         if (!NT_STATUS_IS_OK(status)) {
269                 cli_set_error(cli, status);
270         }
271         return status;
272 }
273
274 /****************************************************************************
275  Read a POSIX symlink.
276 ****************************************************************************/
277
278 struct readlink_state {
279         uint16_t setup;
280         uint8_t *param;
281         uint8_t *data;
282         uint32_t num_data;
283 };
284
285 static void cli_posix_readlink_done(struct tevent_req *subreq)
286 {
287         struct tevent_req *req = tevent_req_callback_data(
288                                 subreq, struct tevent_req);
289         struct readlink_state *state = tevent_req_data(req, struct readlink_state);
290         NTSTATUS status;
291
292         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
293                         &state->data, &state->num_data);
294         TALLOC_FREE(subreq);
295         if (!NT_STATUS_IS_OK(status)) {
296                 tevent_req_nterror(req, status);
297                 return;
298         }
299         if (state->num_data == 0) {
300                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
301                 return;
302         }
303         if (state->data[state->num_data-1] != '\0') {
304                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
305                 return;
306         }
307         tevent_req_done(req);
308 }
309
310 struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
311                                         struct event_context *ev,
312                                         struct cli_state *cli,
313                                         const char *fname,
314                                         size_t len)
315 {
316         struct tevent_req *req = NULL, *subreq = NULL;
317         struct readlink_state *state = NULL;
318         uint32_t maxbytelen = (uint32_t)(cli_ucs2(cli) ? len*3 : len);
319
320         if (maxbytelen < len) {
321                 return NULL;
322         }
323
324         req = tevent_req_create(mem_ctx, &state, struct readlink_state);
325         if (req == NULL) {
326                 return NULL;
327         }
328
329         /* Setup setup word. */
330         SSVAL(&state->setup, 0, TRANSACT2_QPATHINFO);
331
332         /* Setup param array. */
333         state->param = talloc_array(state, uint8_t, 6);
334         if (tevent_req_nomem(state->param, req)) {
335                 return tevent_req_post(req, ev);
336         }
337         memset(state->param, '\0', 6);
338         SSVAL(state->param,0,SMB_QUERY_FILE_UNIX_LINK);
339
340         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
341                                    strlen(fname)+1, NULL);
342
343         if (tevent_req_nomem(state->param, req)) {
344                 return tevent_req_post(req, ev);
345         }
346
347         subreq = cli_trans_send(state,                  /* mem ctx. */
348                                 ev,                     /* event ctx. */
349                                 cli,                    /* cli_state. */
350                                 SMBtrans2,              /* cmd. */
351                                 NULL,                   /* pipe name. */
352                                 -1,                     /* fid. */
353                                 0,                      /* function. */
354                                 0,                      /* flags. */
355                                 &state->setup,          /* setup. */
356                                 1,                      /* num setup uint16_t words. */
357                                 0,                      /* max returned setup. */
358                                 state->param,           /* param. */
359                                 talloc_get_size(state->param),  /* num param. */
360                                 2,                      /* max returned param. */
361                                 NULL,                   /* data. */
362                                 0,                      /* num data. */
363                                 maxbytelen);            /* max returned data. */
364
365         if (tevent_req_nomem(subreq, req)) {
366                 return tevent_req_post(req, ev);
367         }
368         tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
369         return req;
370 }
371
372 NTSTATUS cli_posix_readlink_recv(struct tevent_req *req, struct cli_state *cli,
373                                 char *retpath, size_t len)
374 {
375         NTSTATUS status;
376         char *converted = NULL;
377         size_t converted_size = 0;
378         struct readlink_state *state = tevent_req_data(req, struct readlink_state);
379
380         if (tevent_req_is_nterror(req, &status)) {
381                 return status;
382         }
383         /* The returned data is a pushed string, not raw data. */
384         if (!convert_string_talloc(state,
385                                 cli_ucs2(cli) ? CH_UTF16LE : CH_DOS, 
386                                 CH_UNIX,
387                                 state->data,
388                                 state->num_data,
389                                 &converted,
390                                 &converted_size,
391                                 true)) {
392                 return NT_STATUS_NO_MEMORY;
393         }
394
395         len = MIN(len,converted_size);
396         if (len == 0) {
397                 return NT_STATUS_DATA_ERROR;
398         }
399         memcpy(retpath, converted, len);
400         return NT_STATUS_OK;
401 }
402
403 NTSTATUS cli_posix_readlink(struct cli_state *cli, const char *fname,
404                                 char *linkpath, size_t len)
405 {
406         TALLOC_CTX *frame = talloc_stackframe();
407         struct event_context *ev = NULL;
408         struct tevent_req *req = NULL;
409         NTSTATUS status = NT_STATUS_OK;
410
411         if (cli_has_async_calls(cli)) {
412                 /*
413                  * Can't use sync call while an async call is in flight
414                  */
415                 status = NT_STATUS_INVALID_PARAMETER;
416                 goto fail;
417         }
418
419         ev = event_context_init(frame);
420         if (ev == NULL) {
421                 status = NT_STATUS_NO_MEMORY;
422                 goto fail;
423         }
424
425         /* Len is in bytes, we need it in UCS2 units. */
426         if (2*len < len) {
427                 status = NT_STATUS_INVALID_PARAMETER;
428                 goto fail;
429         }
430
431         req = cli_posix_readlink_send(frame,
432                                 ev,
433                                 cli,
434                                 fname,
435                                 len);
436         if (req == NULL) {
437                 status = NT_STATUS_NO_MEMORY;
438                 goto fail;
439         }
440
441         if (!tevent_req_poll(req, ev)) {
442                 status = map_nt_error_from_unix(errno);
443                 goto fail;
444         }
445
446         status = cli_posix_readlink_recv(req, cli, linkpath, len);
447
448  fail:
449         TALLOC_FREE(frame);
450         if (!NT_STATUS_IS_OK(status)) {
451                 cli_set_error(cli, status);
452         }
453         return status;
454 }
455
456 /****************************************************************************
457  Hard link a file (UNIX extensions).
458 ****************************************************************************/
459
460 struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
461                                         struct event_context *ev,
462                                         struct cli_state *cli,
463                                         const char *oldname,
464                                         const char *newname)
465 {
466         return cli_posix_link_internal_send(mem_ctx, ev, cli,
467                         oldname, newname, true);
468 }
469
470 NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
471 {
472         NTSTATUS status;
473
474         if (tevent_req_is_nterror(req, &status)) {
475                 return status;
476         }
477         return NT_STATUS_OK;
478 }
479
480 NTSTATUS cli_posix_hardlink(struct cli_state *cli,
481                         const char *oldname,
482                         const char *newname)
483 {
484         TALLOC_CTX *frame = talloc_stackframe();
485         struct event_context *ev = NULL;
486         struct tevent_req *req = NULL;
487         NTSTATUS status = NT_STATUS_OK;
488
489         if (cli_has_async_calls(cli)) {
490                 /*
491                  * Can't use sync call while an async call is in flight
492                  */
493                 status = NT_STATUS_INVALID_PARAMETER;
494                 goto fail;
495         }
496
497         ev = event_context_init(frame);
498         if (ev == NULL) {
499                 status = NT_STATUS_NO_MEMORY;
500                 goto fail;
501         }
502
503         req = cli_posix_hardlink_send(frame,
504                                 ev,
505                                 cli,
506                                 oldname,
507                                 newname);
508         if (req == NULL) {
509                 status = NT_STATUS_NO_MEMORY;
510                 goto fail;
511         }
512
513         if (!tevent_req_poll(req, ev)) {
514                 status = map_nt_error_from_unix(errno);
515                 goto fail;
516         }
517
518         status = cli_posix_hardlink_recv(req);
519
520  fail:
521         TALLOC_FREE(frame);
522         if (!NT_STATUS_IS_OK(status)) {
523                 cli_set_error(cli, status);
524         }
525         return status;
526 }
527
528 /****************************************************************************
529  Map standard UNIX permissions onto wire representations.
530 ****************************************************************************/
531
532 uint32_t unix_perms_to_wire(mode_t perms)
533 {
534         unsigned int ret = 0;
535
536         ret |= ((perms & S_IXOTH) ?  UNIX_X_OTH : 0);
537         ret |= ((perms & S_IWOTH) ?  UNIX_W_OTH : 0);
538         ret |= ((perms & S_IROTH) ?  UNIX_R_OTH : 0);
539         ret |= ((perms & S_IXGRP) ?  UNIX_X_GRP : 0);
540         ret |= ((perms & S_IWGRP) ?  UNIX_W_GRP : 0);
541         ret |= ((perms & S_IRGRP) ?  UNIX_R_GRP : 0);
542         ret |= ((perms & S_IXUSR) ?  UNIX_X_USR : 0);
543         ret |= ((perms & S_IWUSR) ?  UNIX_W_USR : 0);
544         ret |= ((perms & S_IRUSR) ?  UNIX_R_USR : 0);
545 #ifdef S_ISVTX
546         ret |= ((perms & S_ISVTX) ?  UNIX_STICKY : 0);
547 #endif
548 #ifdef S_ISGID
549         ret |= ((perms & S_ISGID) ?  UNIX_SET_GID : 0);
550 #endif
551 #ifdef S_ISUID
552         ret |= ((perms & S_ISUID) ?  UNIX_SET_UID : 0);
553 #endif
554         return ret;
555 }
556
557 /****************************************************************************
558  Map wire permissions to standard UNIX.
559 ****************************************************************************/
560
561 mode_t wire_perms_to_unix(uint32_t perms)
562 {
563         mode_t ret = (mode_t)0;
564
565         ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
566         ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
567         ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
568         ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
569         ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
570         ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
571         ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
572         ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
573         ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
574 #ifdef S_ISVTX
575         ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
576 #endif
577 #ifdef S_ISGID
578         ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
579 #endif
580 #ifdef S_ISUID
581         ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
582 #endif
583         return ret;
584 }
585
586 /****************************************************************************
587  Return the file type from the wire filetype for UNIX extensions.
588 ****************************************************************************/
589
590 static mode_t unix_filetype_from_wire(uint32_t wire_type)
591 {
592         switch (wire_type) {
593                 case UNIX_TYPE_FILE:
594                         return S_IFREG;
595                 case UNIX_TYPE_DIR:
596                         return S_IFDIR;
597 #ifdef S_IFLNK
598                 case UNIX_TYPE_SYMLINK:
599                         return S_IFLNK;
600 #endif
601 #ifdef S_IFCHR
602                 case UNIX_TYPE_CHARDEV:
603                         return S_IFCHR;
604 #endif
605 #ifdef S_IFBLK
606                 case UNIX_TYPE_BLKDEV:
607                         return S_IFBLK;
608 #endif
609 #ifdef S_IFIFO
610                 case UNIX_TYPE_FIFO:
611                         return S_IFIFO;
612 #endif
613 #ifdef S_IFSOCK
614                 case UNIX_TYPE_SOCKET:
615                         return S_IFSOCK;
616 #endif
617                 default:
618                         return (mode_t)0;
619         }
620 }
621
622 /****************************************************************************
623  Do a POSIX getfacl (UNIX extensions).
624 ****************************************************************************/
625
626 struct getfacl_state {
627         uint16_t setup;
628         uint8_t *param;
629         uint32_t num_data;
630         uint8_t *data;
631 };
632
633 static void cli_posix_getfacl_done(struct tevent_req *subreq)
634 {
635         struct tevent_req *req = tevent_req_callback_data(
636                                 subreq, struct tevent_req);
637         struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
638         NTSTATUS status;
639
640         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
641                         &state->data, &state->num_data);
642         TALLOC_FREE(subreq);
643         if (!NT_STATUS_IS_OK(status)) {
644                 tevent_req_nterror(req, status);
645                 return;
646         }
647         tevent_req_done(req);
648 }
649
650 struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx,
651                                         struct event_context *ev,
652                                         struct cli_state *cli,
653                                         const char *fname)
654 {
655         struct tevent_req *req = NULL, *subreq = NULL;
656         struct link_state *state = NULL;
657
658         req = tevent_req_create(mem_ctx, &state, struct getfacl_state);
659         if (req == NULL) {
660                 return NULL;
661         }
662
663         /* Setup setup word. */
664         SSVAL(&state->setup, 0, TRANSACT2_QPATHINFO);
665
666         /* Setup param array. */
667         state->param = talloc_array(state, uint8_t, 6);
668         if (tevent_req_nomem(state->param, req)) {
669                 return tevent_req_post(req, ev);
670         }
671         memset(state->param, '\0', 6);
672         SSVAL(state->param, 0, SMB_QUERY_POSIX_ACL);
673
674         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
675                                    strlen(fname)+1, NULL);
676
677         if (tevent_req_nomem(state->param, req)) {
678                 return tevent_req_post(req, ev);
679         }
680
681         subreq = cli_trans_send(state,                  /* mem ctx. */
682                                 ev,                     /* event ctx. */
683                                 cli,                    /* cli_state. */
684                                 SMBtrans2,              /* cmd. */
685                                 NULL,                   /* pipe name. */
686                                 -1,                     /* fid. */
687                                 0,                      /* function. */
688                                 0,                      /* flags. */
689                                 &state->setup,          /* setup. */
690                                 1,                      /* num setup uint16_t words. */
691                                 0,                      /* max returned setup. */
692                                 state->param,           /* param. */
693                                 talloc_get_size(state->param),  /* num param. */
694                                 2,                      /* max returned param. */
695                                 NULL,                   /* data. */
696                                 0,                      /* num data. */
697                                 cli->max_xmit);         /* max returned data. */
698
699         if (tevent_req_nomem(subreq, req)) {
700                 return tevent_req_post(req, ev);
701         }
702         tevent_req_set_callback(subreq, cli_posix_getfacl_done, req);
703         return req;
704 }
705
706 NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req,
707                                 TALLOC_CTX *mem_ctx,
708                                 size_t *prb_size,
709                                 char **retbuf)
710 {
711         struct getfacl_state *state = tevent_req_data(req, struct getfacl_state);
712         NTSTATUS status;
713
714         if (tevent_req_is_nterror(req, &status)) {
715                 return status;
716         }
717         *prb_size = (size_t)state->num_data;
718         *retbuf = (char *)talloc_move(mem_ctx, &state->data);
719         return NT_STATUS_OK;
720 }
721
722 NTSTATUS cli_posix_getfacl(struct cli_state *cli,
723                         const char *fname,
724                         TALLOC_CTX *mem_ctx,
725                         size_t *prb_size,
726                         char **retbuf)
727 {
728         TALLOC_CTX *frame = talloc_stackframe();
729         struct event_context *ev = NULL;
730         struct tevent_req *req = NULL;
731         NTSTATUS status = NT_STATUS_OK;
732
733         if (cli_has_async_calls(cli)) {
734                 /*
735                  * Can't use sync call while an async call is in flight
736                  */
737                 status = NT_STATUS_INVALID_PARAMETER;
738                 goto fail;
739         }
740
741         ev = event_context_init(frame);
742         if (ev == NULL) {
743                 status = NT_STATUS_NO_MEMORY;
744                 goto fail;
745         }
746
747         req = cli_posix_getfacl_send(frame,
748                                 ev,
749                                 cli,
750                                 fname);
751         if (req == NULL) {
752                 status = NT_STATUS_NO_MEMORY;
753                 goto fail;
754         }
755
756         if (!tevent_req_poll(req, ev)) {
757                 status = map_nt_error_from_unix(errno);
758                 goto fail;
759         }
760
761         status = cli_posix_getfacl_recv(req, mem_ctx, prb_size, retbuf);
762
763  fail:
764         TALLOC_FREE(frame);
765         if (!NT_STATUS_IS_OK(status)) {
766                 cli_set_error(cli, status);
767         }
768         return status;
769 }
770
771 /****************************************************************************
772  Stat a file (UNIX extensions).
773 ****************************************************************************/
774
775 struct stat_state {
776         uint16_t setup;
777         uint8_t *param;
778         uint32_t num_data;
779         uint8_t *data;
780 };
781
782 static void cli_posix_stat_done(struct tevent_req *subreq)
783 {
784         struct tevent_req *req = tevent_req_callback_data(
785                                 subreq, struct tevent_req);
786         struct stat_state *state = tevent_req_data(req, struct stat_state);
787         NTSTATUS status;
788
789         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
790                         &state->data, &state->num_data);
791         TALLOC_FREE(subreq);
792         if (!NT_STATUS_IS_OK(status)) {
793                 tevent_req_nterror(req, status);
794                 return;
795         }
796         tevent_req_done(req);
797 }
798
799 struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
800                                         struct event_context *ev,
801                                         struct cli_state *cli,
802                                         const char *fname)
803 {
804         struct tevent_req *req = NULL, *subreq = NULL;
805         struct stat_state *state = NULL;
806
807         req = tevent_req_create(mem_ctx, &state, struct stat_state);
808         if (req == NULL) {
809                 return NULL;
810         }
811
812         /* Setup setup word. */
813         SSVAL(&state->setup, 0, TRANSACT2_QPATHINFO);
814
815         /* Setup param array. */
816         state->param = talloc_array(state, uint8_t, 6);
817         if (tevent_req_nomem(state->param, req)) {
818                 return tevent_req_post(req, ev);
819         }
820         memset(state->param, '\0', 6);
821         SSVAL(state->param, 0, SMB_QUERY_FILE_UNIX_BASIC);
822
823         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
824                                    strlen(fname)+1, NULL);
825
826         if (tevent_req_nomem(state->param, req)) {
827                 return tevent_req_post(req, ev);
828         }
829
830         subreq = cli_trans_send(state,                  /* mem ctx. */
831                                 ev,                     /* event ctx. */
832                                 cli,                    /* cli_state. */
833                                 SMBtrans2,              /* cmd. */
834                                 NULL,                   /* pipe name. */
835                                 -1,                     /* fid. */
836                                 0,                      /* function. */
837                                 0,                      /* flags. */
838                                 &state->setup,          /* setup. */
839                                 1,                      /* num setup uint16_t words. */
840                                 0,                      /* max returned setup. */
841                                 state->param,           /* param. */
842                                 talloc_get_size(state->param),  /* num param. */
843                                 2,                      /* max returned param. */
844                                 NULL,                   /* data. */
845                                 0,                      /* num data. */
846                                 96);                    /* max returned data. */
847
848         if (tevent_req_nomem(subreq, req)) {
849                 return tevent_req_post(req, ev);
850         }
851         tevent_req_set_callback(subreq, cli_posix_stat_done, req);
852         return req;
853 }
854
855 NTSTATUS cli_posix_stat_recv(struct tevent_req *req,
856                                 SMB_STRUCT_STAT *sbuf)
857 {
858         struct stat_state *state = tevent_req_data(req, struct stat_state);
859         NTSTATUS status;
860
861         if (tevent_req_is_nterror(req, &status)) {
862                 return status;
863         }
864
865         if (state->num_data != 96) {
866                 return NT_STATUS_DATA_ERROR;
867         }
868
869         sbuf->st_ex_size = IVAL2_TO_SMB_BIG_UINT(state->data,0);     /* total size, in bytes */
870         sbuf->st_ex_blocks = IVAL2_TO_SMB_BIG_UINT(state->data,8);   /* number of blocks allocated */
871 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
872         sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
873 #else
874         /* assume 512 byte blocks */
875         sbuf->st_ex_blocks /= 512;
876 #endif
877         sbuf->st_ex_ctime = interpret_long_date((char *)(state->data + 16));    /* time of last change */
878         sbuf->st_ex_atime = interpret_long_date((char *)(state->data + 24));    /* time of last access */
879         sbuf->st_ex_mtime = interpret_long_date((char *)(state->data + 32));    /* time of last modification */
880
881         sbuf->st_ex_uid = (uid_t) IVAL(state->data,40);      /* user ID of owner */
882         sbuf->st_ex_gid = (gid_t) IVAL(state->data,48);      /* group ID of owner */
883         sbuf->st_ex_mode = unix_filetype_from_wire(IVAL(state->data, 56));
884 #if defined(HAVE_MAKEDEV)
885         {
886                 uint32_t dev_major = IVAL(state->data,60);
887                 uint32_t dev_minor = IVAL(state->data,68);
888                 sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
889         }
890 #endif
891         sbuf->st_ex_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(state->data,76);      /* inode */
892         sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(state->data,84));     /* protection */
893         sbuf->st_ex_nlink = IVAL(state->data,92);    /* number of hard links */
894
895         return NT_STATUS_OK;
896 }
897
898 NTSTATUS cli_posix_stat(struct cli_state *cli,
899                         const char *fname,
900                         SMB_STRUCT_STAT *sbuf)
901 {
902         TALLOC_CTX *frame = talloc_stackframe();
903         struct event_context *ev = NULL;
904         struct tevent_req *req = NULL;
905         NTSTATUS status = NT_STATUS_OK;
906
907         if (cli_has_async_calls(cli)) {
908                 /*
909                  * Can't use sync call while an async call is in flight
910                  */
911                 status = NT_STATUS_INVALID_PARAMETER;
912                 goto fail;
913         }
914
915         ev = event_context_init(frame);
916         if (ev == NULL) {
917                 status = NT_STATUS_NO_MEMORY;
918                 goto fail;
919         }
920
921         req = cli_posix_stat_send(frame,
922                                 ev,
923                                 cli,
924                                 fname);
925         if (req == NULL) {
926                 status = NT_STATUS_NO_MEMORY;
927                 goto fail;
928         }
929
930         if (!tevent_req_poll(req, ev)) {
931                 status = map_nt_error_from_unix(errno);
932                 goto fail;
933         }
934
935         status = cli_posix_stat_recv(req, sbuf);
936
937  fail:
938         TALLOC_FREE(frame);
939         if (!NT_STATUS_IS_OK(status)) {
940                 cli_set_error(cli, status);
941         }
942         return status;
943 }
944
945 /****************************************************************************
946  Chmod or chown a file internal (UNIX extensions).
947 ****************************************************************************/
948
949 struct ch_state {
950         uint16_t setup;
951         uint8_t *param;
952         uint8_t *data;
953 };
954
955 static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
956 {
957         struct tevent_req *req = tevent_req_callback_data(
958                                 subreq, struct tevent_req);
959         struct ch_state *state = tevent_req_data(req, struct ch_state);
960         NTSTATUS status;
961
962         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, NULL, NULL);
963         TALLOC_FREE(subreq);
964         if (!NT_STATUS_IS_OK(status)) {
965                 tevent_req_nterror(req, status);
966                 return;
967         }
968         tevent_req_done(req);
969 }
970
971 static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
972                                         struct event_context *ev,
973                                         struct cli_state *cli,
974                                         const char *fname,
975                                         uint32_t mode,
976                                         uint32_t uid,
977                                         uint32_t gid)
978 {
979         struct tevent_req *req = NULL, *subreq = NULL;
980         struct ch_state *state = NULL;
981
982         req = tevent_req_create(mem_ctx, &state, struct ch_state);
983         if (req == NULL) {
984                 return NULL;
985         }
986
987         /* Setup setup word. */
988         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
989
990         /* Setup param array. */
991         state->param = talloc_array(state, uint8_t, 6);
992         if (tevent_req_nomem(state->param, req)) {
993                 return tevent_req_post(req, ev);
994         }
995         memset(state->param, '\0', 6);
996         SSVAL(state->param,0,SMB_SET_FILE_UNIX_BASIC);
997
998         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
999                                    strlen(fname)+1, NULL);
1000
1001         if (tevent_req_nomem(state->param, req)) {
1002                 return tevent_req_post(req, ev);
1003         }
1004
1005         /* Setup data array. */
1006         state->data = talloc_array(state, uint8_t, 100);
1007         if (tevent_req_nomem(state->data, req)) {
1008                 return tevent_req_post(req, ev);
1009         }
1010         memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
1011         memset(&state->data[40], '\0', 60);
1012         SIVAL(state->data,40,uid);
1013         SIVAL(state->data,48,gid);
1014         SIVAL(state->data,84,mode);
1015
1016         subreq = cli_trans_send(state,                  /* mem ctx. */
1017                                 ev,                     /* event ctx. */
1018                                 cli,                    /* cli_state. */
1019                                 SMBtrans2,              /* cmd. */
1020                                 NULL,                   /* pipe name. */
1021                                 -1,                     /* fid. */
1022                                 0,                      /* function. */
1023                                 0,                      /* flags. */
1024                                 &state->setup,          /* setup. */
1025                                 1,                      /* num setup uint16_t words. */
1026                                 0,                      /* max returned setup. */
1027                                 state->param,           /* param. */
1028                                 talloc_get_size(state->param),  /* num param. */
1029                                 2,                      /* max returned param. */
1030                                 state->data,            /* data. */
1031                                 talloc_get_size(state->data),   /* num data. */
1032                                 0);                     /* max returned data. */
1033
1034         if (tevent_req_nomem(subreq, req)) {
1035                 return tevent_req_post(req, ev);
1036         }
1037         tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done, req);
1038         return req;
1039 }
1040
1041 /****************************************************************************
1042  chmod a file (UNIX extensions).
1043 ****************************************************************************/
1044
1045 struct tevent_req *cli_posix_chmod_send(TALLOC_CTX *mem_ctx,
1046                                         struct event_context *ev,
1047                                         struct cli_state *cli,
1048                                         const char *fname,
1049                                         mode_t mode)
1050 {
1051         return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
1052                         fname,
1053                         unix_perms_to_wire(mode),
1054                         SMB_UID_NO_CHANGE,
1055                         SMB_GID_NO_CHANGE);
1056 }
1057
1058 NTSTATUS cli_posix_chmod_recv(struct tevent_req *req)
1059 {
1060         NTSTATUS status;
1061
1062         if (tevent_req_is_nterror(req, &status)) {
1063                 return status;
1064         }
1065         return NT_STATUS_OK;
1066 }
1067
1068 NTSTATUS cli_posix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
1069 {
1070         TALLOC_CTX *frame = talloc_stackframe();
1071         struct event_context *ev = NULL;
1072         struct tevent_req *req = NULL;
1073         NTSTATUS status = NT_STATUS_OK;
1074
1075         if (cli_has_async_calls(cli)) {
1076                 /*
1077                  * Can't use sync call while an async call is in flight
1078                  */
1079                 status = NT_STATUS_INVALID_PARAMETER;
1080                 goto fail;
1081         }
1082
1083         ev = event_context_init(frame);
1084         if (ev == NULL) {
1085                 status = NT_STATUS_NO_MEMORY;
1086                 goto fail;
1087         }
1088
1089         req = cli_posix_chmod_send(frame,
1090                                 ev,
1091                                 cli,
1092                                 fname,
1093                                 mode);
1094         if (req == NULL) {
1095                 status = NT_STATUS_NO_MEMORY;
1096                 goto fail;
1097         }
1098
1099         if (!tevent_req_poll(req, ev)) {
1100                 status = map_nt_error_from_unix(errno);
1101                 goto fail;
1102         }
1103
1104         status = cli_posix_chmod_recv(req);
1105
1106  fail:
1107         TALLOC_FREE(frame);
1108         if (!NT_STATUS_IS_OK(status)) {
1109                 cli_set_error(cli, status);
1110         }
1111         return status;
1112 }
1113
1114 /****************************************************************************
1115  chown a file (UNIX extensions).
1116 ****************************************************************************/
1117
1118 struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1119                                         struct event_context *ev,
1120                                         struct cli_state *cli,
1121                                         const char *fname,
1122                                         uid_t uid,
1123                                         gid_t gid)
1124 {
1125         return cli_posix_chown_chmod_internal_send(mem_ctx, ev, cli,
1126                         fname,
1127                         SMB_MODE_NO_CHANGE,
1128                         (uint32_t)uid,
1129                         (uint32_t)gid);
1130 }
1131
1132 NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1133 {
1134         NTSTATUS status;
1135
1136         if (tevent_req_is_nterror(req, &status)) {
1137                 return status;
1138         }
1139         return NT_STATUS_OK;
1140 }
1141
1142 NTSTATUS cli_posix_chown(struct cli_state *cli,
1143                         const char *fname,
1144                         uid_t uid,
1145                         gid_t gid)
1146 {
1147         TALLOC_CTX *frame = talloc_stackframe();
1148         struct event_context *ev = NULL;
1149         struct tevent_req *req = NULL;
1150         NTSTATUS status = NT_STATUS_OK;
1151
1152         if (cli_has_async_calls(cli)) {
1153                 /*
1154                  * Can't use sync call while an async call is in flight
1155                  */
1156                 status = NT_STATUS_INVALID_PARAMETER;
1157                 goto fail;
1158         }
1159
1160         ev = event_context_init(frame);
1161         if (ev == NULL) {
1162                 status = NT_STATUS_NO_MEMORY;
1163                 goto fail;
1164         }
1165
1166         req = cli_posix_chown_send(frame,
1167                                 ev,
1168                                 cli,
1169                                 fname,
1170                                 uid,
1171                                 gid);
1172         if (req == NULL) {
1173                 status = NT_STATUS_NO_MEMORY;
1174                 goto fail;
1175         }
1176
1177         if (!tevent_req_poll(req, ev)) {
1178                 status = map_nt_error_from_unix(errno);
1179                 goto fail;
1180         }
1181
1182         status = cli_posix_chown_recv(req);
1183
1184  fail:
1185         TALLOC_FREE(frame);
1186         if (!NT_STATUS_IS_OK(status)) {
1187                 cli_set_error(cli, status);
1188         }
1189         return status;
1190 }
1191
1192 /****************************************************************************
1193  Rename a file.
1194 ****************************************************************************/
1195
1196 static void cli_rename_done(struct tevent_req *subreq);
1197
1198 struct cli_rename_state {
1199         uint16_t vwv[1];
1200 };
1201
1202 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1203                                 struct event_context *ev,
1204                                 struct cli_state *cli,
1205                                 const char *fname_src,
1206                                 const char *fname_dst)
1207 {
1208         struct tevent_req *req = NULL, *subreq = NULL;
1209         struct cli_rename_state *state = NULL;
1210         uint8_t additional_flags = 0;
1211         uint8_t *bytes = NULL;
1212
1213         req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1214         if (req == NULL) {
1215                 return NULL;
1216         }
1217
1218         SSVAL(state->vwv+0, 0, aSYSTEM | aHIDDEN | aDIR);
1219
1220         bytes = talloc_array(state, uint8_t, 1);
1221         if (tevent_req_nomem(bytes, req)) {
1222                 return tevent_req_post(req, ev);
1223         }
1224         bytes[0] = 4;
1225         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1226                                    strlen(fname_src)+1, NULL);
1227         if (tevent_req_nomem(bytes, req)) {
1228                 return tevent_req_post(req, ev);
1229         }
1230
1231         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1232                         talloc_get_size(bytes)+1);
1233         if (tevent_req_nomem(bytes, req)) {
1234                 return tevent_req_post(req, ev);
1235         }
1236
1237         bytes[talloc_get_size(bytes)-1] = 4;
1238         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1239                                    strlen(fname_dst)+1, NULL);
1240         if (tevent_req_nomem(bytes, req)) {
1241                 return tevent_req_post(req, ev);
1242         }
1243
1244         subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1245                               1, state->vwv, talloc_get_size(bytes), bytes);
1246         if (tevent_req_nomem(subreq, req)) {
1247                 return tevent_req_post(req, ev);
1248         }
1249         tevent_req_set_callback(subreq, cli_rename_done, req);
1250         return req;
1251 }
1252
1253 static void cli_rename_done(struct tevent_req *subreq)
1254 {
1255         struct tevent_req *req = tevent_req_callback_data(
1256                                 subreq, struct tevent_req);
1257         NTSTATUS status;
1258
1259         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1260         TALLOC_FREE(subreq);
1261         if (!NT_STATUS_IS_OK(status)) {
1262                 tevent_req_nterror(req, status);
1263                 return;
1264         }
1265         tevent_req_done(req);
1266 }
1267
1268 NTSTATUS cli_rename_recv(struct tevent_req *req)
1269 {
1270         return tevent_req_simple_recv_ntstatus(req);
1271 }
1272
1273 NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1274 {
1275         TALLOC_CTX *frame = talloc_stackframe();
1276         struct event_context *ev;
1277         struct tevent_req *req;
1278         NTSTATUS status = NT_STATUS_OK;
1279
1280         if (cli_has_async_calls(cli)) {
1281                 /*
1282                  * Can't use sync call while an async call is in flight
1283                  */
1284                 status = NT_STATUS_INVALID_PARAMETER;
1285                 goto fail;
1286         }
1287
1288         ev = event_context_init(frame);
1289         if (ev == NULL) {
1290                 status = NT_STATUS_NO_MEMORY;
1291                 goto fail;
1292         }
1293
1294         req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
1295         if (req == NULL) {
1296                 status = NT_STATUS_NO_MEMORY;
1297                 goto fail;
1298         }
1299
1300         if (!tevent_req_poll(req, ev)) {
1301                 status = map_nt_error_from_unix(errno);
1302                 goto fail;
1303         }
1304
1305         status = cli_rename_recv(req);
1306
1307  fail:
1308         TALLOC_FREE(frame);
1309         if (!NT_STATUS_IS_OK(status)) {
1310                 cli_set_error(cli, status);
1311         }
1312         return status;
1313 }
1314
1315 /****************************************************************************
1316  NT Rename a file.
1317 ****************************************************************************/
1318
1319 static void cli_ntrename_internal_done(struct tevent_req *subreq);
1320
1321 struct cli_ntrename_internal_state {
1322         uint16_t vwv[4];
1323 };
1324
1325 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1326                                 struct event_context *ev,
1327                                 struct cli_state *cli,
1328                                 const char *fname_src,
1329                                 const char *fname_dst,
1330                                 uint16_t rename_flag)
1331 {
1332         struct tevent_req *req = NULL, *subreq = NULL;
1333         struct cli_ntrename_internal_state *state = NULL;
1334         uint8_t additional_flags = 0;
1335         uint8_t *bytes = NULL;
1336
1337         req = tevent_req_create(mem_ctx, &state,
1338                                 struct cli_ntrename_internal_state);
1339         if (req == NULL) {
1340                 return NULL;
1341         }
1342
1343         SSVAL(state->vwv+0, 0 ,aSYSTEM | aHIDDEN | aDIR);
1344         SSVAL(state->vwv+1, 0, rename_flag);
1345
1346         bytes = talloc_array(state, uint8_t, 1);
1347         if (tevent_req_nomem(bytes, req)) {
1348                 return tevent_req_post(req, ev);
1349         }
1350         bytes[0] = 4;
1351         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
1352                                    strlen(fname_src)+1, NULL);
1353         if (tevent_req_nomem(bytes, req)) {
1354                 return tevent_req_post(req, ev);
1355         }
1356
1357         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
1358                         talloc_get_size(bytes)+1);
1359         if (tevent_req_nomem(bytes, req)) {
1360                 return tevent_req_post(req, ev);
1361         }
1362
1363         bytes[talloc_get_size(bytes)-1] = 4;
1364         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
1365                                    strlen(fname_dst)+1, NULL);
1366         if (tevent_req_nomem(bytes, req)) {
1367                 return tevent_req_post(req, ev);
1368         }
1369
1370         subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1371                               4, state->vwv, talloc_get_size(bytes), bytes);
1372         if (tevent_req_nomem(subreq, req)) {
1373                 return tevent_req_post(req, ev);
1374         }
1375         tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1376         return req;
1377 }
1378
1379 static void cli_ntrename_internal_done(struct tevent_req *subreq)
1380 {
1381         struct tevent_req *req = tevent_req_callback_data(
1382                                 subreq, struct tevent_req);
1383         NTSTATUS status;
1384
1385         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1386         TALLOC_FREE(subreq);
1387         if (!NT_STATUS_IS_OK(status)) {
1388                 tevent_req_nterror(req, status);
1389                 return;
1390         }
1391         tevent_req_done(req);
1392 }
1393
1394 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1395 {
1396         return tevent_req_simple_recv_ntstatus(req);
1397 }
1398
1399 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1400                                 struct event_context *ev,
1401                                 struct cli_state *cli,
1402                                 const char *fname_src,
1403                                 const char *fname_dst)
1404 {
1405         return cli_ntrename_internal_send(mem_ctx,
1406                                           ev,
1407                                           cli,
1408                                           fname_src,
1409                                           fname_dst,
1410                                           RENAME_FLAG_RENAME);
1411 }
1412
1413 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
1414 {
1415         return cli_ntrename_internal_recv(req);
1416 }
1417
1418 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1419 {
1420         TALLOC_CTX *frame = talloc_stackframe();
1421         struct event_context *ev;
1422         struct tevent_req *req;
1423         NTSTATUS status = NT_STATUS_OK;
1424
1425         if (cli_has_async_calls(cli)) {
1426                 /*
1427                  * Can't use sync call while an async call is in flight
1428                  */
1429                 status = NT_STATUS_INVALID_PARAMETER;
1430                 goto fail;
1431         }
1432
1433         ev = event_context_init(frame);
1434         if (ev == NULL) {
1435                 status = NT_STATUS_NO_MEMORY;
1436                 goto fail;
1437         }
1438
1439         req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
1440         if (req == NULL) {
1441                 status = NT_STATUS_NO_MEMORY;
1442                 goto fail;
1443         }
1444
1445         if (!tevent_req_poll(req, ev)) {
1446                 status = map_nt_error_from_unix(errno);
1447                 goto fail;
1448         }
1449
1450         status = cli_ntrename_recv(req);
1451
1452  fail:
1453         TALLOC_FREE(frame);
1454         if (!NT_STATUS_IS_OK(status)) {
1455                 cli_set_error(cli, status);
1456         }
1457         return status;
1458 }
1459
1460 /****************************************************************************
1461  NT hardlink a file.
1462 ****************************************************************************/
1463
1464 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
1465                                 struct event_context *ev,
1466                                 struct cli_state *cli,
1467                                 const char *fname_src,
1468                                 const char *fname_dst)
1469 {
1470         return cli_ntrename_internal_send(mem_ctx,
1471                                           ev,
1472                                           cli,
1473                                           fname_src,
1474                                           fname_dst,
1475                                           RENAME_FLAG_HARD_LINK);
1476 }
1477
1478 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
1479 {
1480         return cli_ntrename_internal_recv(req);
1481 }
1482
1483 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
1484 {
1485         TALLOC_CTX *frame = talloc_stackframe();
1486         struct event_context *ev;
1487         struct tevent_req *req;
1488         NTSTATUS status = NT_STATUS_OK;
1489
1490         if (cli_has_async_calls(cli)) {
1491                 /*
1492                  * Can't use sync call while an async call is in flight
1493                  */
1494                 status = NT_STATUS_INVALID_PARAMETER;
1495                 goto fail;
1496         }
1497
1498         ev = event_context_init(frame);
1499         if (ev == NULL) {
1500                 status = NT_STATUS_NO_MEMORY;
1501                 goto fail;
1502         }
1503
1504         req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
1505         if (req == NULL) {
1506                 status = NT_STATUS_NO_MEMORY;
1507                 goto fail;
1508         }
1509
1510         if (!tevent_req_poll(req, ev)) {
1511                 status = map_nt_error_from_unix(errno);
1512                 goto fail;
1513         }
1514
1515         status = cli_nt_hardlink_recv(req);
1516
1517  fail:
1518         TALLOC_FREE(frame);
1519         if (!NT_STATUS_IS_OK(status)) {
1520                 cli_set_error(cli, status);
1521         }
1522         return status;
1523 }
1524
1525 /****************************************************************************
1526  Delete a file.
1527 ****************************************************************************/
1528
1529 static void cli_unlink_done(struct tevent_req *subreq);
1530
1531 struct cli_unlink_state {
1532         uint16_t vwv[1];
1533 };
1534
1535 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
1536                                 struct event_context *ev,
1537                                 struct cli_state *cli,
1538                                 const char *fname,
1539                                 uint16_t mayhave_attrs)
1540 {
1541         struct tevent_req *req = NULL, *subreq = NULL;
1542         struct cli_unlink_state *state = NULL;
1543         uint8_t additional_flags = 0;
1544         uint8_t *bytes = NULL;
1545
1546         req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
1547         if (req == NULL) {
1548                 return NULL;
1549         }
1550
1551         SSVAL(state->vwv+0, 0, mayhave_attrs);
1552
1553         bytes = talloc_array(state, uint8_t, 1);
1554         if (tevent_req_nomem(bytes, req)) {
1555                 return tevent_req_post(req, ev);
1556         }
1557         bytes[0] = 4;
1558         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
1559                                    strlen(fname)+1, NULL);
1560
1561         if (tevent_req_nomem(bytes, req)) {
1562                 return tevent_req_post(req, ev);
1563         }
1564
1565         subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
1566                                 1, state->vwv, talloc_get_size(bytes), bytes);
1567         if (tevent_req_nomem(subreq, req)) {
1568                 return tevent_req_post(req, ev);
1569         }
1570         tevent_req_set_callback(subreq, cli_unlink_done, req);
1571         return req;
1572 }
1573
1574 static void cli_unlink_done(struct tevent_req *subreq)
1575 {
1576         struct tevent_req *req = tevent_req_callback_data(
1577                 subreq, struct tevent_req);
1578         NTSTATUS status;
1579
1580         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1581         TALLOC_FREE(subreq);
1582         if (!NT_STATUS_IS_OK(status)) {
1583                 tevent_req_nterror(req, status);
1584                 return;
1585         }
1586         tevent_req_done(req);
1587 }
1588
1589 NTSTATUS cli_unlink_recv(struct tevent_req *req)
1590 {
1591         return tevent_req_simple_recv_ntstatus(req);
1592 }
1593
1594 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
1595 {
1596         TALLOC_CTX *frame = talloc_stackframe();
1597         struct event_context *ev;
1598         struct tevent_req *req;
1599         NTSTATUS status = NT_STATUS_OK;
1600
1601         if (cli_has_async_calls(cli)) {
1602                 /*
1603                  * Can't use sync call while an async call is in flight
1604                  */
1605                 status = NT_STATUS_INVALID_PARAMETER;
1606                 goto fail;
1607         }
1608
1609         ev = event_context_init(frame);
1610         if (ev == NULL) {
1611                 status = NT_STATUS_NO_MEMORY;
1612                 goto fail;
1613         }
1614
1615         req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
1616         if (req == NULL) {
1617                 status = NT_STATUS_NO_MEMORY;
1618                 goto fail;
1619         }
1620
1621         if (!tevent_req_poll(req, ev)) {
1622                 status = map_nt_error_from_unix(errno);
1623                 goto fail;
1624         }
1625
1626         status = cli_unlink_recv(req);
1627
1628  fail:
1629         TALLOC_FREE(frame);
1630         if (!NT_STATUS_IS_OK(status)) {
1631                 cli_set_error(cli, status);
1632         }
1633         return status;
1634 }
1635
1636 /****************************************************************************
1637  Create a directory.
1638 ****************************************************************************/
1639
1640 static void cli_mkdir_done(struct tevent_req *subreq);
1641
1642 struct cli_mkdir_state {
1643         int dummy;
1644 };
1645
1646 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
1647                                   struct event_context *ev,
1648                                   struct cli_state *cli,
1649                                   const char *dname)
1650 {
1651         struct tevent_req *req = NULL, *subreq = NULL;
1652         struct cli_mkdir_state *state = NULL;
1653         uint8_t additional_flags = 0;
1654         uint8_t *bytes = NULL;
1655
1656         req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
1657         if (req == NULL) {
1658                 return NULL;
1659         }
1660
1661         bytes = talloc_array(state, uint8_t, 1);
1662         if (tevent_req_nomem(bytes, req)) {
1663                 return tevent_req_post(req, ev);
1664         }
1665         bytes[0] = 4;
1666         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1667                                    strlen(dname)+1, NULL);
1668
1669         if (tevent_req_nomem(bytes, req)) {
1670                 return tevent_req_post(req, ev);
1671         }
1672
1673         subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
1674                               0, NULL, talloc_get_size(bytes), bytes);
1675         if (tevent_req_nomem(subreq, req)) {
1676                 return tevent_req_post(req, ev);
1677         }
1678         tevent_req_set_callback(subreq, cli_mkdir_done, req);
1679         return req;
1680 }
1681
1682 static void cli_mkdir_done(struct tevent_req *subreq)
1683 {
1684         struct tevent_req *req = tevent_req_callback_data(
1685                 subreq, struct tevent_req);
1686         NTSTATUS status;
1687
1688         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1689         TALLOC_FREE(subreq);
1690         if (!NT_STATUS_IS_OK(status)) {
1691                 tevent_req_nterror(req, status);
1692                 return;
1693         }
1694         tevent_req_done(req);
1695 }
1696
1697 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
1698 {
1699         return tevent_req_simple_recv_ntstatus(req);
1700 }
1701
1702 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
1703 {
1704         TALLOC_CTX *frame = talloc_stackframe();
1705         struct event_context *ev;
1706         struct tevent_req *req;
1707         NTSTATUS status = NT_STATUS_OK;
1708
1709         if (cli_has_async_calls(cli)) {
1710                 /*
1711                  * Can't use sync call while an async call is in flight
1712                  */
1713                 status = NT_STATUS_INVALID_PARAMETER;
1714                 goto fail;
1715         }
1716
1717         ev = event_context_init(frame);
1718         if (ev == NULL) {
1719                 status = NT_STATUS_NO_MEMORY;
1720                 goto fail;
1721         }
1722
1723         req = cli_mkdir_send(frame, ev, cli, dname);
1724         if (req == NULL) {
1725                 status = NT_STATUS_NO_MEMORY;
1726                 goto fail;
1727         }
1728
1729         if (!tevent_req_poll(req, ev)) {
1730                 status = map_nt_error_from_unix(errno);
1731                 goto fail;
1732         }
1733
1734         status = cli_mkdir_recv(req);
1735
1736  fail:
1737         TALLOC_FREE(frame);
1738         if (!NT_STATUS_IS_OK(status)) {
1739                 cli_set_error(cli, status);
1740         }
1741         return status;
1742 }
1743
1744 /****************************************************************************
1745  Remove a directory.
1746 ****************************************************************************/
1747
1748 static void cli_rmdir_done(struct tevent_req *subreq);
1749
1750 struct cli_rmdir_state {
1751         int dummy;
1752 };
1753
1754 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
1755                                   struct event_context *ev,
1756                                   struct cli_state *cli,
1757                                   const char *dname)
1758 {
1759         struct tevent_req *req = NULL, *subreq = NULL;
1760         struct cli_rmdir_state *state = NULL;
1761         uint8_t additional_flags = 0;
1762         uint8_t *bytes = NULL;
1763
1764         req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1765         if (req == NULL) {
1766                 return NULL;
1767         }
1768
1769         bytes = talloc_array(state, uint8_t, 1);
1770         if (tevent_req_nomem(bytes, req)) {
1771                 return tevent_req_post(req, ev);
1772         }
1773         bytes[0] = 4;
1774         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1775                                    strlen(dname)+1, NULL);
1776
1777         if (tevent_req_nomem(bytes, req)) {
1778                 return tevent_req_post(req, ev);
1779         }
1780
1781         subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1782                               0, NULL, talloc_get_size(bytes), bytes);
1783         if (tevent_req_nomem(subreq, req)) {
1784                 return tevent_req_post(req, ev);
1785         }
1786         tevent_req_set_callback(subreq, cli_rmdir_done, req);
1787         return req;
1788 }
1789
1790 static void cli_rmdir_done(struct tevent_req *subreq)
1791 {
1792         struct tevent_req *req = tevent_req_callback_data(
1793                 subreq, struct tevent_req);
1794         NTSTATUS status;
1795
1796         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1797         TALLOC_FREE(subreq);
1798         if (!NT_STATUS_IS_OK(status)) {
1799                 tevent_req_nterror(req, status);
1800                 return;
1801         }
1802         tevent_req_done(req);
1803 }
1804
1805 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1806 {
1807         return tevent_req_simple_recv_ntstatus(req);
1808 }
1809
1810 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1811 {
1812         TALLOC_CTX *frame = talloc_stackframe();
1813         struct event_context *ev;
1814         struct tevent_req *req;
1815         NTSTATUS status = NT_STATUS_OK;
1816
1817         if (cli_has_async_calls(cli)) {
1818                 /*
1819                  * Can't use sync call while an async call is in flight
1820                  */
1821                 status = NT_STATUS_INVALID_PARAMETER;
1822                 goto fail;
1823         }
1824
1825         ev = event_context_init(frame);
1826         if (ev == NULL) {
1827                 status = NT_STATUS_NO_MEMORY;
1828                 goto fail;
1829         }
1830
1831         req = cli_rmdir_send(frame, ev, cli, dname);
1832         if (req == NULL) {
1833                 status = NT_STATUS_NO_MEMORY;
1834                 goto fail;
1835         }
1836
1837         if (!tevent_req_poll(req, ev)) {
1838                 status = map_nt_error_from_unix(errno);
1839                 goto fail;
1840         }
1841
1842         status = cli_rmdir_recv(req);
1843
1844  fail:
1845         TALLOC_FREE(frame);
1846         if (!NT_STATUS_IS_OK(status)) {
1847                 cli_set_error(cli, status);
1848         }
1849         return status;
1850 }
1851
1852 /****************************************************************************
1853  Set or clear the delete on close flag.
1854 ****************************************************************************/
1855
1856 struct doc_state {
1857         uint16_t setup;
1858         uint8_t param[6];
1859         uint8_t data[1];
1860 };
1861
1862 static void cli_nt_delete_on_close_done(struct tevent_req *subreq)
1863 {
1864         struct tevent_req *req = tevent_req_callback_data(
1865                                 subreq, struct tevent_req);
1866         struct doc_state *state = tevent_req_data(req, struct doc_state);
1867         NTSTATUS status;
1868
1869         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, NULL, NULL);
1870         TALLOC_FREE(subreq);
1871         if (!NT_STATUS_IS_OK(status)) {
1872                 tevent_req_nterror(req, status);
1873                 return;
1874         }
1875         tevent_req_done(req);
1876 }
1877
1878 struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
1879                                         struct event_context *ev,
1880                                         struct cli_state *cli,
1881                                         uint16_t fnum,
1882                                         bool flag)
1883 {
1884         struct tevent_req *req = NULL, *subreq = NULL;
1885         struct doc_state *state = NULL;
1886
1887         req = tevent_req_create(mem_ctx, &state, struct doc_state);
1888         if (req == NULL) {
1889                 return NULL;
1890         }
1891
1892         /* Setup setup word. */
1893         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
1894
1895         /* Setup param array. */
1896         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 struct cli_ntcreate_state {
1985         uint16_t vwv[24];
1986         uint16_t fnum;
1987 };
1988
1989 static void cli_ntcreate_done(struct tevent_req *subreq);
1990
1991 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
1992                                      struct event_context *ev,
1993                                      struct cli_state *cli,
1994                                      const char *fname,
1995                                      uint32_t CreatFlags,
1996                                      uint32_t DesiredAccess,
1997                                      uint32_t FileAttributes,
1998                                      uint32_t ShareAccess,
1999                                      uint32_t CreateDisposition,
2000                                      uint32_t CreateOptions,
2001                                      uint8_t SecurityFlags)
2002 {
2003         struct tevent_req *req, *subreq;
2004         struct cli_ntcreate_state *state;
2005         uint16_t *vwv;
2006         uint8_t *bytes;
2007         size_t converted_len;
2008
2009         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
2010         if (req == NULL) {
2011                 return NULL;
2012         }
2013         vwv = state->vwv;
2014
2015         SCVAL(vwv+0, 0, 0xFF);
2016         SCVAL(vwv+0, 1, 0);
2017         SSVAL(vwv+1, 0, 0);
2018         SCVAL(vwv+2, 0, 0);
2019
2020         if (cli->use_oplocks) {
2021                 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
2022         }
2023         SIVAL(vwv+3, 1, CreatFlags);
2024         SIVAL(vwv+5, 1, 0x0);   /* RootDirectoryFid */
2025         SIVAL(vwv+7, 1, DesiredAccess);
2026         SIVAL(vwv+9, 1, 0x0);   /* AllocationSize */
2027         SIVAL(vwv+11, 1, 0x0);  /* AllocationSize */
2028         SIVAL(vwv+13, 1, FileAttributes);
2029         SIVAL(vwv+15, 1, ShareAccess);
2030         SIVAL(vwv+17, 1, CreateDisposition);
2031         SIVAL(vwv+19, 1, CreateOptions);
2032         SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
2033         SCVAL(vwv+23, 1, SecurityFlags);
2034
2035         bytes = talloc_array(state, uint8_t, 0);
2036         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
2037                                    fname, strlen(fname)+1,
2038                                    &converted_len);
2039
2040         /* sigh. this copes with broken netapp filer behaviour */
2041         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL);
2042
2043         if (tevent_req_nomem(bytes, req)) {
2044                 return tevent_req_post(req, ev);
2045         }
2046
2047         SIVAL(vwv+2, 1, converted_len);
2048
2049         subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
2050                               talloc_get_size(bytes), bytes);
2051         if (tevent_req_nomem(subreq, req)) {
2052                 return tevent_req_post(req, ev);
2053         }
2054         tevent_req_set_callback(subreq, cli_ntcreate_done, req);
2055         return req;
2056 }
2057
2058 static void cli_ntcreate_done(struct tevent_req *subreq)
2059 {
2060         struct tevent_req *req = tevent_req_callback_data(
2061                 subreq, struct tevent_req);
2062         struct cli_ntcreate_state *state = tevent_req_data(
2063                 req, struct cli_ntcreate_state);
2064         uint8_t wct;
2065         uint16_t *vwv;
2066         uint32_t num_bytes;
2067         uint8_t *bytes;
2068         NTSTATUS status;
2069
2070         status = cli_smb_recv(subreq, 3, &wct, &vwv, &num_bytes, &bytes);
2071         if (!NT_STATUS_IS_OK(status)) {
2072                 TALLOC_FREE(subreq);
2073                 tevent_req_nterror(req, status);
2074                 return;
2075         }
2076         state->fnum = SVAL(vwv+2, 1);
2077         tevent_req_done(req);
2078 }
2079
2080 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
2081 {
2082         struct cli_ntcreate_state *state = tevent_req_data(
2083                 req, struct cli_ntcreate_state);
2084         NTSTATUS status;
2085
2086         if (tevent_req_is_nterror(req, &status)) {
2087                 return status;
2088         }
2089         *pfnum = state->fnum;
2090         return NT_STATUS_OK;
2091 }
2092
2093 NTSTATUS cli_ntcreate(struct cli_state *cli,
2094                       const char *fname,
2095                       uint32_t CreatFlags,
2096                       uint32_t DesiredAccess,
2097                       uint32_t FileAttributes,
2098                       uint32_t ShareAccess,
2099                       uint32_t CreateDisposition,
2100                       uint32_t CreateOptions,
2101                       uint8_t SecurityFlags,
2102                       uint16_t *pfid)
2103 {
2104         TALLOC_CTX *frame = talloc_stackframe();
2105         struct event_context *ev;
2106         struct tevent_req *req;
2107         NTSTATUS status = NT_STATUS_OK;
2108
2109         if (cli_has_async_calls(cli)) {
2110                 /*
2111                  * Can't use sync call while an async call is in flight
2112                  */
2113                 status = NT_STATUS_INVALID_PARAMETER;
2114                 goto fail;
2115         }
2116
2117         ev = event_context_init(frame);
2118         if (ev == NULL) {
2119                 status = NT_STATUS_NO_MEMORY;
2120                 goto fail;
2121         }
2122
2123         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2124                                 DesiredAccess, FileAttributes, ShareAccess,
2125                                 CreateDisposition, CreateOptions,
2126                                 SecurityFlags);
2127         if (req == NULL) {
2128                 status = NT_STATUS_NO_MEMORY;
2129                 goto fail;
2130         }
2131
2132         if (!tevent_req_poll(req, ev)) {
2133                 status = map_nt_error_from_unix(errno);
2134                 goto fail;
2135         }
2136
2137         status = cli_ntcreate_recv(req, pfid);
2138  fail:
2139         TALLOC_FREE(frame);
2140         if (!NT_STATUS_IS_OK(status)) {
2141                 cli_set_error(cli, status);
2142         }
2143         return status;
2144 }
2145
2146 /****************************************************************************
2147  Open a file
2148  WARNING: if you open with O_WRONLY then getattrE won't work!
2149 ****************************************************************************/
2150
2151 struct cli_open_state {
2152         uint16_t vwv[15];
2153         uint16_t fnum;
2154         struct iovec bytes;
2155 };
2156
2157 static void cli_open_done(struct tevent_req *subreq);
2158
2159 struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx,
2160                                    struct event_context *ev,
2161                                    struct cli_state *cli, const char *fname,
2162                                    int flags, int share_mode,
2163                                    struct tevent_req **psmbreq)
2164 {
2165         struct tevent_req *req, *subreq;
2166         struct cli_open_state *state;
2167         unsigned openfn;
2168         unsigned accessmode;
2169         uint8_t additional_flags;
2170         uint8_t *bytes;
2171
2172         req = tevent_req_create(mem_ctx, &state, struct cli_open_state);
2173         if (req == NULL) {
2174                 return NULL;
2175         }
2176
2177         openfn = 0;
2178         if (flags & O_CREAT) {
2179                 openfn |= (1<<4);
2180         }
2181         if (!(flags & O_EXCL)) {
2182                 if (flags & O_TRUNC)
2183                         openfn |= (1<<1);
2184                 else
2185                         openfn |= (1<<0);
2186         }
2187
2188         accessmode = (share_mode<<4);
2189
2190         if ((flags & O_ACCMODE) == O_RDWR) {
2191                 accessmode |= 2;
2192         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2193                 accessmode |= 1;
2194         }
2195
2196 #if defined(O_SYNC)
2197         if ((flags & O_SYNC) == O_SYNC) {
2198                 accessmode |= (1<<14);
2199         }
2200 #endif /* O_SYNC */
2201
2202         if (share_mode == DENY_FCB) {
2203                 accessmode = 0xFF;
2204         }
2205
2206         SCVAL(state->vwv + 0, 0, 0xFF);
2207         SCVAL(state->vwv + 0, 1, 0);
2208         SSVAL(state->vwv + 1, 0, 0);
2209         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
2210         SSVAL(state->vwv + 3, 0, accessmode);
2211         SSVAL(state->vwv + 4, 0, aSYSTEM | aHIDDEN);
2212         SSVAL(state->vwv + 5, 0, 0);
2213         SIVAL(state->vwv + 6, 0, 0);
2214         SSVAL(state->vwv + 8, 0, openfn);
2215         SIVAL(state->vwv + 9, 0, 0);
2216         SIVAL(state->vwv + 11, 0, 0);
2217         SIVAL(state->vwv + 13, 0, 0);
2218
2219         additional_flags = 0;
2220
2221         if (cli->use_oplocks) {
2222                 /* if using oplocks then ask for a batch oplock via
2223                    core and extended methods */
2224                 additional_flags =
2225                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2226                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2227         }
2228
2229         bytes = talloc_array(state, uint8_t, 0);
2230         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
2231                                    strlen(fname)+1, NULL);
2232
2233         if (tevent_req_nomem(bytes, req)) {
2234                 return tevent_req_post(req, ev);
2235         }
2236
2237         state->bytes.iov_base = (void *)bytes;
2238         state->bytes.iov_len = talloc_get_size(bytes);
2239
2240         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2241                                     15, state->vwv, 1, &state->bytes);
2242         if (subreq == NULL) {
2243                 TALLOC_FREE(req);
2244                 return NULL;
2245         }
2246         tevent_req_set_callback(subreq, cli_open_done, req);
2247         *psmbreq = subreq;
2248         return req;
2249 }
2250
2251 struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
2252                                  struct cli_state *cli, const char *fname,
2253                                  int flags, int share_mode)
2254 {
2255         struct tevent_req *req, *subreq;
2256         NTSTATUS status;
2257
2258         req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode,
2259                               &subreq);
2260         if (req == NULL) {
2261                 return NULL;
2262         }
2263
2264         status = cli_smb_req_send(subreq);
2265         if (!NT_STATUS_IS_OK(status)) {
2266                 tevent_req_nterror(req, status);
2267                 return tevent_req_post(req, ev);
2268         }
2269         return req;
2270 }
2271
2272 static void cli_open_done(struct tevent_req *subreq)
2273 {
2274         struct tevent_req *req = tevent_req_callback_data(
2275                 subreq, struct tevent_req);
2276         struct cli_open_state *state = tevent_req_data(
2277                 req, struct cli_open_state);
2278         uint8_t wct;
2279         uint16_t *vwv;
2280         NTSTATUS status;
2281
2282         status = cli_smb_recv(subreq, 3, &wct, &vwv, NULL, NULL);
2283         if (!NT_STATUS_IS_OK(status)) {
2284                 TALLOC_FREE(subreq);
2285                 tevent_req_nterror(req, status);
2286                 return;
2287         }
2288         state->fnum = SVAL(vwv+2, 0);
2289         tevent_req_done(req);
2290 }
2291
2292 NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum)
2293 {
2294         struct cli_open_state *state = tevent_req_data(
2295                 req, struct cli_open_state);
2296         NTSTATUS status;
2297
2298         if (tevent_req_is_nterror(req, &status)) {
2299                 return status;
2300         }
2301         *pfnum = state->fnum;
2302         return NT_STATUS_OK;
2303 }
2304
2305 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2306              int share_mode, uint16_t *pfnum)
2307 {
2308         TALLOC_CTX *frame = talloc_stackframe();
2309         struct event_context *ev;
2310         struct tevent_req *req;
2311         NTSTATUS status = NT_STATUS_OK;
2312
2313         if (cli_has_async_calls(cli)) {
2314                 /*
2315                  * Can't use sync call while an async call is in flight
2316                  */
2317                 status = NT_STATUS_INVALID_PARAMETER;
2318                 goto fail;
2319         }
2320
2321         ev = event_context_init(frame);
2322         if (ev == NULL) {
2323                 status = NT_STATUS_NO_MEMORY;
2324                 goto fail;
2325         }
2326
2327         req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
2328         if (req == NULL) {
2329                 status = NT_STATUS_NO_MEMORY;
2330                 goto fail;
2331         }
2332
2333         if (!tevent_req_poll(req, ev)) {
2334                 status = map_nt_error_from_unix(errno);
2335                 goto fail;
2336         }
2337
2338         status = cli_open_recv(req, pfnum);
2339  fail:
2340         TALLOC_FREE(frame);
2341         if (!NT_STATUS_IS_OK(status)) {
2342                 cli_set_error(cli, status);
2343         }
2344         return status;
2345 }
2346
2347 /****************************************************************************
2348  Close a file.
2349 ****************************************************************************/
2350
2351 struct cli_close_state {
2352         uint16_t vwv[3];
2353 };
2354
2355 static void cli_close_done(struct tevent_req *subreq);
2356
2357 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2358                                 struct event_context *ev,
2359                                 struct cli_state *cli,
2360                                 uint16_t fnum,
2361                                 struct tevent_req **psubreq)
2362 {
2363         struct tevent_req *req, *subreq;
2364         struct cli_close_state *state;
2365
2366         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2367         if (req == NULL) {
2368                 return NULL;
2369         }
2370         SSVAL(state->vwv+0, 0, fnum);
2371         SIVALS(state->vwv+1, 0, -1);
2372
2373         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2374                                     0, NULL);
2375         if (subreq == NULL) {
2376                 TALLOC_FREE(req);
2377                 return NULL;
2378         }
2379         tevent_req_set_callback(subreq, cli_close_done, req);
2380         *psubreq = subreq;
2381         return req;
2382 }
2383
2384 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2385                                 struct event_context *ev,
2386                                 struct cli_state *cli,
2387                                 uint16_t fnum)
2388 {
2389         struct tevent_req *req, *subreq;
2390         NTSTATUS status;
2391
2392         req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2393         if (req == NULL) {
2394                 return NULL;
2395         }
2396
2397         status = cli_smb_req_send(subreq);
2398         if (!NT_STATUS_IS_OK(status)) {
2399                 tevent_req_nterror(req, status);
2400                 return tevent_req_post(req, ev);
2401         }
2402         return req;
2403 }
2404
2405 static void cli_close_done(struct tevent_req *subreq)
2406 {
2407         struct tevent_req *req = tevent_req_callback_data(
2408                 subreq, struct tevent_req);
2409         NTSTATUS status;
2410
2411         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2412         TALLOC_FREE(subreq);
2413         if (!NT_STATUS_IS_OK(status)) {
2414                 tevent_req_nterror(req, status);
2415                 return;
2416         }
2417         tevent_req_done(req);
2418 }
2419
2420 NTSTATUS cli_close_recv(struct tevent_req *req)
2421 {
2422         return tevent_req_simple_recv_ntstatus(req);
2423 }
2424
2425 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2426 {
2427         TALLOC_CTX *frame = talloc_stackframe();
2428         struct event_context *ev;
2429         struct tevent_req *req;
2430         NTSTATUS status = NT_STATUS_OK;
2431
2432         if (cli_has_async_calls(cli)) {
2433                 /*
2434                  * Can't use sync call while an async call is in flight
2435                  */
2436                 status = NT_STATUS_INVALID_PARAMETER;
2437                 goto fail;
2438         }
2439
2440         ev = event_context_init(frame);
2441         if (ev == NULL) {
2442                 status = NT_STATUS_NO_MEMORY;
2443                 goto fail;
2444         }
2445
2446         req = cli_close_send(frame, ev, cli, fnum);
2447         if (req == NULL) {
2448                 status = NT_STATUS_NO_MEMORY;
2449                 goto fail;
2450         }
2451
2452         if (!tevent_req_poll(req, ev)) {
2453                 status = map_nt_error_from_unix(errno);
2454                 goto fail;
2455         }
2456
2457         status = cli_close_recv(req);
2458  fail:
2459         TALLOC_FREE(frame);
2460         if (!NT_STATUS_IS_OK(status)) {
2461                 cli_set_error(cli, status);
2462         }
2463         return status;
2464 }
2465
2466 /****************************************************************************
2467  Truncate a file to a specified size
2468 ****************************************************************************/
2469
2470 struct ftrunc_state {
2471         uint16_t setup;
2472         uint8_t param[6];
2473         uint8_t data[8];
2474 };
2475
2476 static void cli_ftruncate_done(struct tevent_req *subreq)
2477 {
2478         struct tevent_req *req = tevent_req_callback_data(
2479                                 subreq, struct tevent_req);
2480         struct ftrunc_state *state = tevent_req_data(req, struct ftrunc_state);
2481         NTSTATUS status;
2482
2483         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, NULL, NULL);
2484         TALLOC_FREE(subreq);
2485         if (!NT_STATUS_IS_OK(status)) {
2486                 tevent_req_nterror(req, status);
2487                 return;
2488         }
2489         tevent_req_done(req);
2490 }
2491
2492 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2493                                         struct event_context *ev,
2494                                         struct cli_state *cli,
2495                                         uint16_t fnum,
2496                                         uint64_t size)
2497 {
2498         struct tevent_req *req = NULL, *subreq = NULL;
2499         struct ftrunc_state *state = NULL;
2500
2501         req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2502         if (req == NULL) {
2503                 return NULL;
2504         }
2505
2506         /* Setup setup word. */
2507         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2508
2509         /* Setup param array. */
2510         SSVAL(state->param,0,fnum);
2511         SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2512         SSVAL(state->param,4,0);
2513
2514         /* Setup data array. */
2515         SBVAL(state->data, 0, size);
2516
2517         subreq = cli_trans_send(state,                  /* mem ctx. */
2518                                 ev,                     /* event ctx. */
2519                                 cli,                    /* cli_state. */
2520                                 SMBtrans2,              /* cmd. */
2521                                 NULL,                   /* pipe name. */
2522                                 -1,                     /* fid. */
2523                                 0,                      /* function. */
2524                                 0,                      /* flags. */
2525                                 &state->setup,          /* setup. */
2526                                 1,                      /* num setup uint16_t words. */
2527                                 0,                      /* max returned setup. */
2528                                 state->param,           /* param. */
2529                                 6,                      /* num param. */
2530                                 2,                      /* max returned param. */
2531                                 state->data,            /* data. */
2532                                 8,                      /* num data. */
2533                                 0);                     /* max returned data. */
2534
2535         if (tevent_req_nomem(subreq, req)) {
2536                 return tevent_req_post(req, ev);
2537         }
2538         tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2539         return req;
2540 }
2541
2542 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2543 {
2544         NTSTATUS status;
2545
2546         if (tevent_req_is_nterror(req, &status)) {
2547                 return status;
2548         }
2549         return NT_STATUS_OK;
2550 }
2551
2552 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2553 {
2554         TALLOC_CTX *frame = talloc_stackframe();
2555         struct event_context *ev = NULL;
2556         struct tevent_req *req = NULL;
2557         NTSTATUS status = NT_STATUS_OK;
2558
2559         if (cli_has_async_calls(cli)) {
2560                 /*
2561                  * Can't use sync call while an async call is in flight
2562                  */
2563                 status = NT_STATUS_INVALID_PARAMETER;
2564                 goto fail;
2565         }
2566
2567         ev = event_context_init(frame);
2568         if (ev == NULL) {
2569                 status = NT_STATUS_NO_MEMORY;
2570                 goto fail;
2571         }
2572
2573         req = cli_ftruncate_send(frame,
2574                                 ev,
2575                                 cli,
2576                                 fnum,
2577                                 size);
2578         if (req == NULL) {
2579                 status = NT_STATUS_NO_MEMORY;
2580                 goto fail;
2581         }
2582
2583         if (!tevent_req_poll(req, ev)) {
2584                 status = map_nt_error_from_unix(errno);
2585                 goto fail;
2586         }
2587
2588         status = cli_ftruncate_recv(req);
2589
2590  fail:
2591         TALLOC_FREE(frame);
2592         if (!NT_STATUS_IS_OK(status)) {
2593                 cli_set_error(cli, status);
2594         }
2595         return status;
2596 }
2597
2598 /****************************************************************************
2599  send a lock with a specified locktype
2600  this is used for testing LOCKING_ANDX_CANCEL_LOCK
2601 ****************************************************************************/
2602
2603 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2604                       uint32_t offset, uint32_t len,
2605                       int timeout, unsigned char locktype)
2606 {
2607         char *p;
2608         int saved_timeout = cli->timeout;
2609
2610         memset(cli->outbuf,'\0',smb_size);
2611         memset(cli->inbuf,'\0', smb_size);
2612
2613         cli_set_message(cli->outbuf,8,0,True);
2614
2615         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2616         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2617         cli_setup_packet(cli);
2618
2619         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2620         SSVAL(cli->outbuf,smb_vwv2,fnum);
2621         SCVAL(cli->outbuf,smb_vwv3,locktype);
2622         SIVALS(cli->outbuf, smb_vwv4, timeout);
2623         SSVAL(cli->outbuf,smb_vwv6,0);
2624         SSVAL(cli->outbuf,smb_vwv7,1);
2625
2626         p = smb_buf(cli->outbuf);
2627         SSVAL(p, 0, cli->pid);
2628         SIVAL(p, 2, offset);
2629         SIVAL(p, 6, len);
2630
2631         p += 10;
2632
2633         cli_setup_bcc(cli, p);
2634
2635         cli_send_smb(cli);
2636
2637         if (timeout != 0) {
2638                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
2639         }
2640
2641         if (!cli_receive_smb(cli)) {
2642                 cli->timeout = saved_timeout;
2643                 return NT_STATUS_UNSUCCESSFUL;
2644         }
2645
2646         cli->timeout = saved_timeout;
2647
2648         return cli_nt_error(cli);
2649 }
2650
2651 /****************************************************************************
2652  Lock a file.
2653  note that timeout is in units of 2 milliseconds
2654 ****************************************************************************/
2655
2656 bool cli_lock(struct cli_state *cli, uint16_t fnum,
2657               uint32_t offset, uint32_t len, int timeout, enum brl_type lock_type)
2658 {
2659         char *p;
2660         int saved_timeout = cli->timeout;
2661
2662         memset(cli->outbuf,'\0',smb_size);
2663         memset(cli->inbuf,'\0', smb_size);
2664
2665         cli_set_message(cli->outbuf,8,0,True);
2666
2667         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2668         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2669         cli_setup_packet(cli);
2670
2671         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2672         SSVAL(cli->outbuf,smb_vwv2,fnum);
2673         SCVAL(cli->outbuf,smb_vwv3,(lock_type == READ_LOCK? 1 : 0));
2674         SIVALS(cli->outbuf, smb_vwv4, timeout);
2675         SSVAL(cli->outbuf,smb_vwv6,0);
2676         SSVAL(cli->outbuf,smb_vwv7,1);
2677
2678         p = smb_buf(cli->outbuf);
2679         SSVAL(p, 0, cli->pid);
2680         SIVAL(p, 2, offset);
2681         SIVAL(p, 6, len);
2682
2683         p += 10;
2684
2685         cli_setup_bcc(cli, p);
2686
2687         cli_send_smb(cli);
2688
2689         if (timeout != 0) {
2690                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout*2 + 5*1000);
2691         }
2692
2693         if (!cli_receive_smb(cli)) {
2694                 cli->timeout = saved_timeout;
2695                 return False;
2696         }
2697
2698         cli->timeout = saved_timeout;
2699
2700         if (cli_is_error(cli)) {
2701                 return False;
2702         }
2703
2704         return True;
2705 }
2706
2707 /****************************************************************************
2708  Unlock a file.
2709 ****************************************************************************/
2710
2711 bool cli_unlock(struct cli_state *cli, uint16_t fnum, uint32_t offset, uint32_t len)
2712 {
2713         char *p;
2714
2715         memset(cli->outbuf,'\0',smb_size);
2716         memset(cli->inbuf,'\0',smb_size);
2717
2718         cli_set_message(cli->outbuf,8,0,True);
2719
2720         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2721         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2722         cli_setup_packet(cli);
2723
2724         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2725         SSVAL(cli->outbuf,smb_vwv2,fnum);
2726         SCVAL(cli->outbuf,smb_vwv3,0);
2727         SIVALS(cli->outbuf, smb_vwv4, 0);
2728         SSVAL(cli->outbuf,smb_vwv6,1);
2729         SSVAL(cli->outbuf,smb_vwv7,0);
2730
2731         p = smb_buf(cli->outbuf);
2732         SSVAL(p, 0, cli->pid);
2733         SIVAL(p, 2, offset);
2734         SIVAL(p, 6, len);
2735         p += 10;
2736         cli_setup_bcc(cli, p);
2737         cli_send_smb(cli);
2738         if (!cli_receive_smb(cli)) {
2739                 return False;
2740         }
2741
2742         if (cli_is_error(cli)) {
2743                 return False;
2744         }
2745
2746         return True;
2747 }
2748
2749 /****************************************************************************
2750  Lock a file with 64 bit offsets.
2751 ****************************************************************************/
2752
2753 bool cli_lock64(struct cli_state *cli, uint16_t fnum,
2754                 uint64_t offset, uint64_t len, int timeout, enum brl_type lock_type)
2755 {
2756         char *p;
2757         int saved_timeout = cli->timeout;
2758         int ltype;
2759
2760         if (! (cli->capabilities & CAP_LARGE_FILES)) {
2761                 return cli_lock(cli, fnum, offset, len, timeout, lock_type);
2762         }
2763
2764         ltype = (lock_type == READ_LOCK? 1 : 0);
2765         ltype |= LOCKING_ANDX_LARGE_FILES;
2766
2767         memset(cli->outbuf,'\0',smb_size);
2768         memset(cli->inbuf,'\0', smb_size);
2769
2770         cli_set_message(cli->outbuf,8,0,True);
2771
2772         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2773         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2774         cli_setup_packet(cli);
2775
2776         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2777         SSVAL(cli->outbuf,smb_vwv2,fnum);
2778         SCVAL(cli->outbuf,smb_vwv3,ltype);
2779         SIVALS(cli->outbuf, smb_vwv4, timeout);
2780         SSVAL(cli->outbuf,smb_vwv6,0);
2781         SSVAL(cli->outbuf,smb_vwv7,1);
2782
2783         p = smb_buf(cli->outbuf);
2784         SIVAL(p, 0, cli->pid);
2785         SOFF_T_R(p, 4, offset);
2786         SOFF_T_R(p, 12, len);
2787         p += 20;
2788
2789         cli_setup_bcc(cli, p);
2790         cli_send_smb(cli);
2791
2792         if (timeout != 0) {
2793                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 5*1000);
2794         }
2795
2796         if (!cli_receive_smb(cli)) {
2797                 cli->timeout = saved_timeout;
2798                 return False;
2799         }
2800
2801         cli->timeout = saved_timeout;
2802
2803         if (cli_is_error(cli)) {
2804                 return False;
2805         }
2806
2807         return True;
2808 }
2809
2810 /****************************************************************************
2811  Unlock a file with 64 bit offsets.
2812 ****************************************************************************/
2813
2814 bool cli_unlock64(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
2815 {
2816         char *p;
2817
2818         if (! (cli->capabilities & CAP_LARGE_FILES)) {
2819                 return cli_unlock(cli, fnum, offset, len);
2820         }
2821
2822         memset(cli->outbuf,'\0',smb_size);
2823         memset(cli->inbuf,'\0',smb_size);
2824
2825         cli_set_message(cli->outbuf,8,0,True);
2826
2827         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2828         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2829         cli_setup_packet(cli);
2830
2831         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2832         SSVAL(cli->outbuf,smb_vwv2,fnum);
2833         SCVAL(cli->outbuf,smb_vwv3,LOCKING_ANDX_LARGE_FILES);
2834         SIVALS(cli->outbuf, smb_vwv4, 0);
2835         SSVAL(cli->outbuf,smb_vwv6,1);
2836         SSVAL(cli->outbuf,smb_vwv7,0);
2837
2838         p = smb_buf(cli->outbuf);
2839         SIVAL(p, 0, cli->pid);
2840         SOFF_T_R(p, 4, offset);
2841         SOFF_T_R(p, 12, len);
2842         p += 20;
2843         cli_setup_bcc(cli, p);
2844         cli_send_smb(cli);
2845         if (!cli_receive_smb(cli)) {
2846                 return False;
2847         }
2848
2849         if (cli_is_error(cli)) {
2850                 return False;
2851         }
2852
2853         return True;
2854 }
2855
2856 /****************************************************************************
2857  Get/unlock a POSIX lock on a file - internal function.
2858 ****************************************************************************/
2859
2860 static bool cli_posix_lock_internal(struct cli_state *cli, uint16_t fnum,
2861                 uint64_t offset, uint64_t len, bool wait_lock, enum brl_type lock_type)
2862 {
2863         unsigned int param_len = 4;
2864         unsigned int data_len = POSIX_LOCK_DATA_SIZE;
2865         uint16_t setup = TRANSACT2_SETFILEINFO;
2866         char param[4];
2867         unsigned char data[POSIX_LOCK_DATA_SIZE];
2868         char *rparam=NULL, *rdata=NULL;
2869         int saved_timeout = cli->timeout;
2870
2871         SSVAL(param,0,fnum);
2872         SSVAL(param,2,SMB_SET_POSIX_LOCK);
2873
2874         switch (lock_type) {
2875                 case READ_LOCK:
2876                         SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_READ);
2877                         break;
2878                 case WRITE_LOCK:
2879                         SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_WRITE);
2880                         break;
2881                 case UNLOCK_LOCK:
2882                         SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
2883                         break;
2884                 default:
2885                         return False;
2886         }
2887
2888         if (wait_lock) {
2889                 SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_WAIT);
2890                 cli->timeout = 0x7FFFFFFF;
2891         } else {
2892                 SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_NOWAIT);
2893         }
2894
2895         SIVAL(data, POSIX_LOCK_PID_OFFSET, cli->pid);
2896         SOFF_T(data, POSIX_LOCK_START_OFFSET, offset);
2897         SOFF_T(data, POSIX_LOCK_LEN_OFFSET, len);
2898
2899         if (!cli_send_trans(cli, SMBtrans2,
2900                         NULL,                        /* name */
2901                         -1, 0,                          /* fid, flags */
2902                         &setup, 1, 0,                   /* setup, length, max */
2903                         param, param_len, 2,            /* param, length, max */
2904                         (char *)&data,  data_len, cli->max_xmit /* data, length, max */
2905                         )) {
2906                 cli->timeout = saved_timeout;
2907                 return False;
2908         }
2909
2910         if (!cli_receive_trans(cli, SMBtrans2,
2911                                 &rparam, &param_len,
2912                                 &rdata, &data_len)) {
2913                 cli->timeout = saved_timeout;
2914                 SAFE_FREE(rdata);
2915                 SAFE_FREE(rparam);
2916                 return False;
2917         }
2918
2919         cli->timeout = saved_timeout;
2920
2921         SAFE_FREE(rdata);
2922         SAFE_FREE(rparam);
2923
2924         return True;
2925 }
2926
2927 /****************************************************************************
2928  POSIX Lock a file.
2929 ****************************************************************************/
2930
2931 bool cli_posix_lock(struct cli_state *cli, uint16_t fnum,
2932                         uint64_t offset, uint64_t len,
2933                         bool wait_lock, enum brl_type lock_type)
2934 {
2935         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
2936                 return False;
2937         }
2938         return cli_posix_lock_internal(cli, fnum, offset, len, wait_lock, lock_type);
2939 }
2940
2941 /****************************************************************************
2942  POSIX Unlock a file.
2943 ****************************************************************************/
2944
2945 bool cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
2946 {
2947         return cli_posix_lock_internal(cli, fnum, offset, len, False, UNLOCK_LOCK);
2948 }
2949
2950 /****************************************************************************
2951  POSIX Get any lock covering a file.
2952 ****************************************************************************/
2953
2954 bool cli_posix_getlock(struct cli_state *cli, uint16_t fnum, uint64_t *poffset, uint64_t *plen)
2955 {
2956         return True;
2957 }
2958
2959 /****************************************************************************
2960  Do a SMBgetattrE call.
2961 ****************************************************************************/
2962
2963 static void cli_getattrE_done(struct tevent_req *subreq);
2964
2965 struct cli_getattrE_state {
2966         uint16_t vwv[1];
2967         int zone_offset;
2968         uint16_t attr;
2969         SMB_OFF_T size;
2970         time_t change_time;
2971         time_t access_time;
2972         time_t write_time;
2973 };
2974
2975 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
2976                                 struct event_context *ev,
2977                                 struct cli_state *cli,
2978                                 uint16_t fnum)
2979 {
2980         struct tevent_req *req = NULL, *subreq = NULL;
2981         struct cli_getattrE_state *state = NULL;
2982         uint8_t additional_flags = 0;
2983
2984         req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
2985         if (req == NULL) {
2986                 return NULL;
2987         }
2988
2989         state->zone_offset = cli->serverzone;
2990         SSVAL(state->vwv+0,0,fnum);
2991
2992         subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
2993                               1, state->vwv, 0, NULL);
2994         if (tevent_req_nomem(subreq, req)) {
2995                 return tevent_req_post(req, ev);
2996         }
2997         tevent_req_set_callback(subreq, cli_getattrE_done, req);
2998         return req;
2999 }
3000
3001 static void cli_getattrE_done(struct tevent_req *subreq)
3002 {
3003         struct tevent_req *req = tevent_req_callback_data(
3004                 subreq, struct tevent_req);
3005         struct cli_getattrE_state *state = tevent_req_data(
3006                 req, struct cli_getattrE_state);
3007         uint8_t wct;
3008         uint16_t *vwv = NULL;
3009         NTSTATUS status;
3010
3011         status = cli_smb_recv(subreq, 11, &wct, &vwv, NULL, NULL);
3012         if (!NT_STATUS_IS_OK(status)) {
3013                 tevent_req_nterror(req, status);
3014                 return;
3015         }
3016
3017         state->size = (SMB_OFF_T)IVAL(vwv+6,0);
3018         state->attr = SVAL(vwv+10,0);
3019         state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3020         state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3021         state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3022
3023         TALLOC_FREE(subreq);
3024         tevent_req_done(req);
3025 }
3026
3027 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3028                         uint16_t *attr,
3029                         SMB_OFF_T *size,
3030                         time_t *change_time,
3031                         time_t *access_time,
3032                         time_t *write_time)
3033 {
3034         struct cli_getattrE_state *state = tevent_req_data(
3035                                 req, struct cli_getattrE_state);
3036         NTSTATUS status;
3037
3038         if (tevent_req_is_nterror(req, &status)) {
3039                 return status;
3040         }
3041         if (attr) {
3042                 *attr = state->attr;
3043         }
3044         if (size) {
3045                 *size = state->size;
3046         }
3047         if (change_time) {
3048                 *change_time = state->change_time;
3049         }
3050         if (access_time) {
3051                 *access_time = state->access_time;
3052         }
3053         if (write_time) {
3054                 *write_time = state->write_time;
3055         }
3056         return NT_STATUS_OK;
3057 }
3058
3059 NTSTATUS cli_getattrE(struct cli_state *cli,
3060                         uint16_t fnum,
3061                         uint16_t *attr,
3062                         SMB_OFF_T *size,
3063                         time_t *change_time,
3064                         time_t *access_time,
3065                         time_t *write_time)
3066 {
3067         TALLOC_CTX *frame = talloc_stackframe();
3068         struct event_context *ev = NULL;
3069         struct tevent_req *req = NULL;
3070         NTSTATUS status = NT_STATUS_OK;
3071
3072         if (cli_has_async_calls(cli)) {
3073                 /*
3074                  * Can't use sync call while an async call is in flight
3075                  */
3076                 status = NT_STATUS_INVALID_PARAMETER;
3077                 goto fail;
3078         }
3079
3080         ev = event_context_init(frame);
3081         if (ev == NULL) {
3082                 status = NT_STATUS_NO_MEMORY;
3083                 goto fail;
3084         }
3085
3086         req = cli_getattrE_send(frame, ev, cli, fnum);
3087         if (req == NULL) {
3088                 status = NT_STATUS_NO_MEMORY;
3089                 goto fail;
3090         }
3091
3092         if (!tevent_req_poll(req, ev)) {
3093                 status = map_nt_error_from_unix(errno);
3094                 goto fail;
3095         }
3096
3097         status = cli_getattrE_recv(req,
3098                                         attr,
3099                                         size,
3100                                         change_time,
3101                                         access_time,
3102                                         write_time);
3103
3104  fail:
3105         TALLOC_FREE(frame);
3106         if (!NT_STATUS_IS_OK(status)) {
3107                 cli_set_error(cli, status);
3108         }
3109         return status;
3110 }
3111
3112 /****************************************************************************
3113  Do a SMBgetatr call
3114 ****************************************************************************/
3115
3116 static void cli_getatr_done(struct tevent_req *subreq);
3117
3118 struct cli_getatr_state {
3119         int zone_offset;
3120         uint16_t attr;
3121         SMB_OFF_T size;
3122         time_t write_time;
3123 };
3124
3125 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3126                                 struct event_context *ev,
3127                                 struct cli_state *cli,
3128                                 const char *fname)
3129 {
3130         struct tevent_req *req = NULL, *subreq = NULL;
3131         struct cli_getatr_state *state = NULL;
3132         uint8_t additional_flags = 0;
3133         uint8_t *bytes = NULL;
3134
3135         req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3136         if (req == NULL) {
3137                 return NULL;
3138         }
3139
3140         state->zone_offset = cli->serverzone;
3141
3142         bytes = talloc_array(state, uint8_t, 1);
3143         if (tevent_req_nomem(bytes, req)) {
3144                 return tevent_req_post(req, ev);
3145         }
3146         bytes[0] = 4;
3147         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3148                                    strlen(fname)+1, NULL);
3149
3150         if (tevent_req_nomem(bytes, req)) {
3151                 return tevent_req_post(req, ev);
3152         }
3153
3154         subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3155                               0, NULL, talloc_get_size(bytes), bytes);
3156         if (tevent_req_nomem(subreq, req)) {
3157                 return tevent_req_post(req, ev);
3158         }
3159         tevent_req_set_callback(subreq, cli_getatr_done, req);
3160         return req;
3161 }
3162
3163 static void cli_getatr_done(struct tevent_req *subreq)
3164 {
3165         struct tevent_req *req = tevent_req_callback_data(
3166                 subreq, struct tevent_req);
3167         struct cli_getatr_state *state = tevent_req_data(
3168                 req, struct cli_getatr_state);
3169         uint8_t wct;
3170         uint16_t *vwv = NULL;
3171         NTSTATUS status;
3172
3173         status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL);
3174         if (!NT_STATUS_IS_OK(status)) {
3175                 tevent_req_nterror(req, status);
3176                 return;
3177         }
3178
3179         state->attr = SVAL(vwv+0,0);
3180         state->size = (SMB_OFF_T)IVAL(vwv+3,0);
3181         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3182
3183         TALLOC_FREE(subreq);
3184         tevent_req_done(req);
3185 }
3186
3187 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3188                         uint16_t *attr,
3189                         SMB_OFF_T *size,
3190                         time_t *write_time)
3191 {
3192         struct cli_getatr_state *state = tevent_req_data(
3193                                 req, struct cli_getatr_state);
3194         NTSTATUS status;
3195
3196         if (tevent_req_is_nterror(req, &status)) {
3197                 return status;
3198         }
3199         if (attr) {
3200                 *attr = state->attr;
3201         }
3202         if (size) {
3203                 *size = state->size;
3204         }
3205         if (write_time) {
3206                 *write_time = state->write_time;
3207         }
3208         return NT_STATUS_OK;
3209 }
3210
3211 NTSTATUS cli_getatr(struct cli_state *cli,
3212                         const char *fname,
3213                         uint16_t *attr,
3214                         SMB_OFF_T *size,
3215                         time_t *write_time)
3216 {
3217         TALLOC_CTX *frame = talloc_stackframe();
3218         struct event_context *ev = NULL;
3219         struct tevent_req *req = NULL;
3220         NTSTATUS status = NT_STATUS_OK;
3221
3222         if (cli_has_async_calls(cli)) {
3223                 /*
3224                  * Can't use sync call while an async call is in flight
3225                  */
3226                 status = NT_STATUS_INVALID_PARAMETER;
3227                 goto fail;
3228         }
3229
3230         ev = event_context_init(frame);
3231         if (ev == NULL) {
3232                 status = NT_STATUS_NO_MEMORY;
3233                 goto fail;
3234         }
3235
3236         req = cli_getatr_send(frame, ev, cli, fname);
3237         if (req == NULL) {
3238                 status = NT_STATUS_NO_MEMORY;
3239                 goto fail;
3240         }
3241
3242         if (!tevent_req_poll(req, ev)) {
3243                 status = map_nt_error_from_unix(errno);
3244                 goto fail;
3245         }
3246
3247         status = cli_getatr_recv(req,
3248                                 attr,
3249                                 size,
3250                                 write_time);
3251
3252  fail:
3253         TALLOC_FREE(frame);
3254         if (!NT_STATUS_IS_OK(status)) {
3255                 cli_set_error(cli, status);
3256         }
3257         return status;
3258 }
3259
3260 /****************************************************************************
3261  Do a SMBsetattrE call.
3262 ****************************************************************************/
3263
3264 static void cli_setattrE_done(struct tevent_req *subreq);
3265
3266 struct cli_setattrE_state {
3267         int dummy;
3268 };
3269
3270 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3271                                 struct event_context *ev,
3272                                 struct cli_state *cli,
3273                                 uint16_t fnum,
3274                                 time_t change_time,
3275                                 time_t access_time,
3276                                 time_t write_time)
3277 {
3278         struct tevent_req *req = NULL, *subreq = NULL;
3279         struct cli_setattrE_state *state = NULL;
3280         uint8_t additional_flags = 0;
3281         uint16_t vwv[7];
3282
3283         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3284         if (req == NULL) {
3285                 return NULL;
3286         }
3287
3288         memset(vwv, '\0', sizeof(vwv));
3289         SSVAL(vwv+0, 0, fnum);
3290         cli_put_dos_date2(cli, (char *)&vwv[1], 0, change_time);
3291         cli_put_dos_date2(cli, (char *)&vwv[3], 0, access_time);
3292         cli_put_dos_date2(cli, (char *)&vwv[5], 0, write_time);
3293
3294         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3295                               7, vwv, 0, NULL);
3296         if (tevent_req_nomem(subreq, req)) {
3297                 return tevent_req_post(req, ev);
3298         }
3299         tevent_req_set_callback(subreq, cli_setattrE_done, req);
3300         return req;
3301 }
3302
3303 static void cli_setattrE_done(struct tevent_req *subreq)
3304 {
3305         struct tevent_req *req = tevent_req_callback_data(
3306                 subreq, struct tevent_req);
3307         NTSTATUS status;
3308
3309         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
3310         TALLOC_FREE(subreq);
3311         if (!NT_STATUS_IS_OK(status)) {
3312                 tevent_req_nterror(req, status);
3313                 return;
3314         }
3315         tevent_req_done(req);
3316 }
3317
3318 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3319 {
3320         return tevent_req_simple_recv_ntstatus(req);