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