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