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