s3: Initialize output vars in parse_ea_blob
[kai/samba.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "async_smb.h"
23
24 /***********************************************************
25  Common function for pushing stings, used by smb_bytes_push_str()
26  and trans_bytes_push_str(). Only difference is the align_odd
27  parameter setting.
28 ***********************************************************/
29
30 static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
31                                 const char *str, size_t str_len,
32                                 bool align_odd,
33                                 size_t *pconverted_size)
34 {
35         size_t buflen;
36         char *converted;
37         size_t converted_size;
38
39         if (buf == NULL) {
40                 return NULL;
41         }
42
43         buflen = talloc_get_size(buf);
44
45         if (align_odd && ucs2 && (buflen % 2 == 0)) {
46                 /*
47                  * We're pushing into an SMB buffer, align odd
48                  */
49                 buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
50                 if (buf == NULL) {
51                         return NULL;
52                 }
53                 buf[buflen] = '\0';
54                 buflen += 1;
55         }
56
57         if (!convert_string_talloc(talloc_tos(), CH_UNIX,
58                                    ucs2 ? CH_UTF16LE : CH_DOS,
59                                    str, str_len, &converted,
60                                    &converted_size, true)) {
61                 return NULL;
62         }
63
64         buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
65                                    buflen + converted_size);
66         if (buf == NULL) {
67                 TALLOC_FREE(converted);
68                 return NULL;
69         }
70
71         memcpy(buf + buflen, converted, converted_size);
72
73         TALLOC_FREE(converted);
74
75         if (pconverted_size) {
76                 *pconverted_size = converted_size;
77         }
78
79         return buf;
80 }
81
82 /***********************************************************
83  Push a string into an SMB buffer, with odd byte alignment
84  if it's a UCS2 string.
85 ***********************************************************/
86
87 uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
88                             const char *str, size_t str_len,
89                             size_t *pconverted_size)
90 {
91         return internal_bytes_push_str(buf, ucs2, str, str_len,
92                         true, pconverted_size);
93 }
94
95 uint8_t *smb_bytes_push_bytes(uint8_t *buf, uint8_t prefix,
96                               const uint8_t *bytes, size_t num_bytes)
97 {
98         size_t buflen;
99
100         if (buf == NULL) {
101                 return NULL;
102         }
103         buflen = talloc_get_size(buf);
104
105         buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
106                                    buflen + 1 + num_bytes);
107         if (buf == NULL) {
108                 return NULL;
109         }
110         buf[buflen] = prefix;
111         memcpy(&buf[buflen+1], bytes, num_bytes);
112         return buf;
113 }
114
115 /***********************************************************
116  Same as smb_bytes_push_str(), but without the odd byte
117  align for ucs2 (we're pushing into a param or data block).
118  static for now, although this will probably change when
119  other modules use async trans calls.
120 ***********************************************************/
121
122 static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
123                             const char *str, size_t str_len,
124                             size_t *pconverted_size)
125 {
126         return internal_bytes_push_str(buf, ucs2, str, str_len,
127                         false, pconverted_size);
128 }
129
130 /****************************************************************************
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 *ctx, const uint8_t *rdata,
4210                           size_t rdata_len,
4211                           size_t *pnum_eas, struct ea_struct **pea_list)
4212 {
4213         struct ea_struct *ea_list = NULL;
4214         size_t num_eas;
4215         size_t ea_size;
4216         const uint8_t *p;
4217
4218         if (rdata_len < 4) {
4219                 return false;
4220         }
4221
4222         ea_size = (size_t)IVAL(rdata,0);
4223         if (ea_size > rdata_len) {
4224                 return false;
4225         }
4226
4227         if (ea_size == 0) {
4228                 /* No EA's present. */
4229                 *pnum_eas = 0;
4230                 *pea_list = NULL;
4231                 return true;
4232         }
4233
4234         p = rdata + 4;
4235         ea_size -= 4;
4236
4237         /* Validate the EA list and count it. */
4238         for (num_eas = 0; ea_size >= 4; num_eas++) {
4239                 unsigned int ea_namelen = CVAL(p,1);
4240                 unsigned int ea_valuelen = SVAL(p,2);
4241                 if (ea_namelen == 0) {
4242                         return false;
4243                 }
4244                 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4245                         return false;
4246                 }
4247                 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4248                 p += 4 + ea_namelen + 1 + ea_valuelen;
4249         }
4250
4251         if (num_eas == 0) {
4252                 *pnum_eas = 0;
4253                 *pea_list = NULL;
4254                 return true;
4255         }
4256
4257         *pnum_eas = num_eas;
4258         if (!pea_list) {
4259                 /* Caller only wants number of EA's. */
4260                 return true;
4261         }
4262
4263         ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
4264         if (!ea_list) {
4265                 return false;
4266         }
4267
4268         ea_size = (size_t)IVAL(rdata,0);
4269         p = rdata + 4;
4270
4271         for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4272                 struct ea_struct *ea = &ea_list[num_eas];
4273                 fstring unix_ea_name;
4274                 unsigned int ea_namelen = CVAL(p,1);
4275                 unsigned int ea_valuelen = SVAL(p,2);
4276
4277                 ea->flags = CVAL(p,0);
4278                 unix_ea_name[0] = '\0';
4279                 pull_ascii_fstring(unix_ea_name, p + 4);
4280                 ea->name = talloc_strdup(ea_list, unix_ea_name);
4281                 if (!ea->name) {
4282                         goto fail;
4283                 }
4284                 /* Ensure the value is null terminated (in case it's a string). */
4285                 ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
4286                 if (!ea->value.data) {
4287                         goto fail;
4288                 }
4289                 if (ea_valuelen) {
4290                         memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4291                 }
4292                 ea->value.data[ea_valuelen] = 0;
4293                 ea->value.length--;
4294                 p += 4 + ea_namelen + 1 + ea_valuelen;
4295         }
4296
4297         *pea_list = ea_list;
4298         return true;
4299
4300 fail:
4301         TALLOC_FREE(ea_list);
4302         return false;
4303 }
4304
4305 /*********************************************************
4306  Get an extended attribute list from a pathname.
4307 *********************************************************/
4308
4309 struct cli_get_ea_list_path_state {
4310         uint32_t num_data;
4311         uint8_t *data;
4312 };
4313
4314 static void cli_get_ea_list_path_done(struct tevent_req *subreq);
4315
4316 struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
4317                                              struct tevent_context *ev,
4318                                              struct cli_state *cli,
4319                                              const char *fname)
4320 {
4321         struct tevent_req *req, *subreq;
4322         struct cli_get_ea_list_path_state *state;
4323
4324         req = tevent_req_create(mem_ctx, &state,
4325                                 struct cli_get_ea_list_path_state);
4326         if (req == NULL) {
4327                 return NULL;
4328         }
4329         subreq = cli_qpathinfo_send(state, ev, cli, fname,
4330                                     SMB_INFO_QUERY_ALL_EAS, 4,
4331                                     cli->max_xmit);
4332         if (tevent_req_nomem(subreq, req)) {
4333                 return tevent_req_post(req, ev);
4334         }
4335         tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
4336         return req;
4337 }
4338
4339 static void cli_get_ea_list_path_done(struct tevent_req *subreq)
4340 {
4341         struct tevent_req *req = tevent_req_callback_data(
4342                                 subreq, struct tevent_req);
4343         struct cli_get_ea_list_path_state *state = tevent_req_data(
4344                 req, struct cli_get_ea_list_path_state);
4345         NTSTATUS status;
4346
4347         status = cli_qpathinfo_recv(subreq, state, &state->data,
4348                                     &state->num_data);
4349         TALLOC_FREE(subreq);
4350         if (!NT_STATUS_IS_OK(status)) {
4351                 tevent_req_nterror(req, status);
4352                 return;
4353         }
4354         tevent_req_done(req);
4355 }
4356
4357 NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
4358                                    size_t *pnum_eas, struct ea_struct **peas)
4359 {
4360         struct cli_get_ea_list_path_state *state = tevent_req_data(
4361                 req, struct cli_get_ea_list_path_state);
4362         NTSTATUS status;
4363
4364         if (tevent_req_is_nterror(req, &status)) {
4365                 return status;
4366         }
4367         if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
4368                            pnum_eas, peas)) {
4369                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
4370         }
4371         return NT_STATUS_OK;
4372 }
4373
4374 NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
4375                 TALLOC_CTX *ctx,
4376                 size_t *pnum_eas,
4377                 struct ea_struct **pea_list)
4378 {
4379         TALLOC_CTX *frame = talloc_stackframe();
4380         struct event_context *ev = NULL;
4381         struct tevent_req *req = NULL;
4382         NTSTATUS status = NT_STATUS_NO_MEMORY;
4383
4384         if (cli_has_async_calls(cli)) {
4385                 /*
4386                  * Can't use sync call while an async call is in flight
4387                  */
4388                 status = NT_STATUS_INVALID_PARAMETER;
4389                 goto fail;
4390         }
4391         ev = event_context_init(frame);
4392         if (ev == NULL) {
4393                 goto fail;
4394         }
4395         req = cli_get_ea_list_path_send(frame, ev, cli, path);
4396         if (req == NULL) {
4397                 goto fail;
4398         }
4399         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4400                 goto fail;
4401         }
4402         status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
4403  fail:
4404         TALLOC_FREE(frame);
4405         if (!NT_STATUS_IS_OK(status)) {
4406                 cli_set_error(cli, status);
4407         }
4408         return status;
4409 }
4410
4411 /****************************************************************************
4412  Convert open "flags" arg to uint32_t on wire.
4413 ****************************************************************************/
4414
4415 static uint32_t open_flags_to_wire(int flags)
4416 {
4417         int open_mode = flags & O_ACCMODE;
4418         uint32_t ret = 0;
4419
4420         switch (open_mode) {
4421                 case O_WRONLY:
4422                         ret |= SMB_O_WRONLY;
4423                         break;
4424                 case O_RDWR:
4425                         ret |= SMB_O_RDWR;
4426                         break;
4427                 default:
4428                 case O_RDONLY:
4429                         ret |= SMB_O_RDONLY;
4430                         break;
4431         }
4432
4433         if (flags & O_CREAT) {
4434                 ret |= SMB_O_CREAT;
4435         }
4436         if (flags & O_EXCL) {
4437                 ret |= SMB_O_EXCL;
4438         }
4439         if (flags & O_TRUNC) {
4440                 ret |= SMB_O_TRUNC;
4441         }
4442 #if defined(O_SYNC)
4443         if (flags & O_SYNC) {
4444                 ret |= SMB_O_SYNC;
4445         }
4446 #endif /* O_SYNC */
4447         if (flags & O_APPEND) {
4448                 ret |= SMB_O_APPEND;
4449         }
4450 #if defined(O_DIRECT)
4451         if (flags & O_DIRECT) {
4452                 ret |= SMB_O_DIRECT;
4453         }
4454 #endif
4455 #if defined(O_DIRECTORY)
4456         if (flags & O_DIRECTORY) {
4457                 ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4458                 ret |= SMB_O_DIRECTORY;
4459         }
4460 #endif
4461         return ret;
4462 }
4463
4464 /****************************************************************************
4465  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4466 ****************************************************************************/
4467
4468 struct posix_open_state {
4469         uint16_t setup;
4470         uint8_t *param;
4471         uint8_t data[18];
4472         uint16_t fnum; /* Out */
4473 };
4474
4475 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4476 {
4477         struct tevent_req *req = tevent_req_callback_data(
4478                                 subreq, struct tevent_req);
4479         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4480         NTSTATUS status;
4481         uint8_t *data;
4482         uint32_t num_data;
4483
4484         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
4485                                 NULL, 0, NULL, &data, 12, &num_data);
4486         TALLOC_FREE(subreq);
4487         if (!NT_STATUS_IS_OK(status)) {
4488                 tevent_req_nterror(req, status);
4489                 return;
4490         }
4491         state->fnum = SVAL(data,2);
4492         tevent_req_done(req);
4493 }
4494
4495 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4496                                         struct event_context *ev,
4497                                         struct cli_state *cli,
4498                                         const char *fname,
4499                                         int flags,
4500                                         mode_t mode,
4501                                         bool is_dir)
4502 {
4503         struct tevent_req *req = NULL, *subreq = NULL;
4504         struct posix_open_state *state = NULL;
4505         uint32_t wire_flags = open_flags_to_wire(flags);
4506
4507         req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4508         if (req == NULL) {
4509                 return NULL;
4510         }
4511
4512         /* Setup setup word. */
4513         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4514
4515         /* Setup param array. */
4516         state->param = talloc_array(state, uint8_t, 6);
4517         if (tevent_req_nomem(state->param, req)) {
4518                 return tevent_req_post(req, ev);
4519         }
4520         memset(state->param, '\0', 6);
4521         SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4522
4523         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
4524                                    strlen(fname)+1, NULL);
4525
4526         if (tevent_req_nomem(state->param, req)) {
4527                 return tevent_req_post(req, ev);
4528         }
4529
4530         /* Setup data words. */
4531         if (is_dir) {
4532                 wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4533                 wire_flags |= SMB_O_DIRECTORY;
4534         }
4535
4536         SIVAL(state->data,0,0); /* No oplock. */
4537         SIVAL(state->data,4,wire_flags);
4538         SIVAL(state->data,8,unix_perms_to_wire(mode));
4539         SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
4540         SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
4541
4542         subreq = cli_trans_send(state,                  /* mem ctx. */
4543                                 ev,                     /* event ctx. */
4544                                 cli,                    /* cli_state. */
4545                                 SMBtrans2,              /* cmd. */
4546                                 NULL,                   /* pipe name. */
4547                                 -1,                     /* fid. */
4548                                 0,                      /* function. */
4549                                 0,                      /* flags. */
4550                                 &state->setup,          /* setup. */
4551                                 1,                      /* num setup uint16_t words. */
4552                                 0,                      /* max returned setup. */
4553                                 state->param,           /* param. */
4554                                 talloc_get_size(state->param),/* num param. */
4555                                 2,                      /* max returned param. */
4556                                 state->data,            /* data. */
4557                                 18,                     /* num data. */
4558                                 12);                    /* max returned data. */
4559
4560         if (tevent_req_nomem(subreq, req)) {
4561                 return tevent_req_post(req, ev);
4562         }
4563         tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
4564         return req;
4565 }
4566
4567 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
4568                                         struct event_context *ev,
4569                                         struct cli_state *cli,
4570                                         const char *fname,
4571                                         int flags,
4572                                         mode_t mode)
4573 {
4574         return cli_posix_open_internal_send(mem_ctx, ev,
4575                                 cli, fname, flags, mode, false);
4576 }
4577
4578 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
4579 {
4580         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4581         NTSTATUS status;
4582
4583         if (tevent_req_is_nterror(req, &status)) {
4584                 return status;
4585         }
4586         *pfnum = state->fnum;
4587         return NT_STATUS_OK;
4588 }
4589
4590 /****************************************************************************
4591  Open - POSIX semantics. Doesn't request oplock.
4592 ****************************************************************************/
4593
4594 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
4595                         int flags, mode_t mode, uint16_t *pfnum)
4596 {
4597
4598         TALLOC_CTX *frame = talloc_stackframe();
4599         struct event_context *ev = NULL;
4600         struct tevent_req *req = NULL;
4601         NTSTATUS status = NT_STATUS_OK;
4602
4603         if (cli_has_async_calls(cli)) {
4604                 /*
4605                  * Can't use sync call while an async call is in flight
4606                  */
4607                 status = NT_STATUS_INVALID_PARAMETER;
4608                 goto fail;
4609         }
4610
4611         ev = event_context_init(frame);
4612         if (ev == NULL) {
4613                 status = NT_STATUS_NO_MEMORY;
4614                 goto fail;
4615         }
4616
4617         req = cli_posix_open_send(frame,
4618                                 ev,
4619                                 cli,
4620                                 fname,
4621                                 flags,
4622                                 mode);
4623         if (req == NULL) {
4624                 status = NT_STATUS_NO_MEMORY;
4625                 goto fail;
4626         }
4627
4628         if (!tevent_req_poll(req, ev)) {
4629                 status = map_nt_error_from_unix(errno);
4630                 goto fail;
4631         }
4632
4633         status = cli_posix_open_recv(req, pfnum);
4634
4635  fail:
4636         TALLOC_FREE(frame);
4637         if (!NT_STATUS_IS_OK(status)) {
4638                 cli_set_error(cli, status);
4639         }
4640         return status;
4641 }
4642
4643 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
4644                                         struct event_context *ev,
4645                                         struct cli_state *cli,
4646                                         const char *fname,
4647                                         mode_t mode)
4648 {
4649         return cli_posix_open_internal_send(mem_ctx, ev,
4650                                 cli, fname, O_CREAT, mode, true);
4651 }
4652
4653 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
4654 {
4655         NTSTATUS status;
4656
4657         if (tevent_req_is_nterror(req, &status)) {
4658                 return status;
4659         }
4660         return NT_STATUS_OK;
4661 }
4662
4663 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
4664 {
4665         TALLOC_CTX *frame = talloc_stackframe();
4666         struct event_context *ev = NULL;
4667         struct tevent_req *req = NULL;
4668         NTSTATUS status = NT_STATUS_OK;
4669
4670         if (cli_has_async_calls(cli)) {
4671                 /*
4672                  * Can't use sync call while an async call is in flight
4673                  */
4674                 status = NT_STATUS_INVALID_PARAMETER;
4675                 goto fail;
4676         }
4677
4678         ev = event_context_init(frame);
4679         if (ev == NULL) {
4680                 status = NT_STATUS_NO_MEMORY;
4681                 goto fail;
4682         }
4683
4684         req = cli_posix_mkdir_send(frame,
4685                                 ev,
4686                                 cli,
4687                                 fname,
4688                                 mode);
4689         if (req == NULL) {
4690                 status = NT_STATUS_NO_MEMORY;
4691                 goto fail;
4692         }
4693
4694         if (!tevent_req_poll(req, ev)) {
4695                 status = map_nt_error_from_unix(errno);
4696                 goto fail;
4697         }
4698
4699         status = cli_posix_mkdir_recv(req);
4700
4701  fail:
4702         TALLOC_FREE(frame);
4703         if (!NT_STATUS_IS_OK(status)) {
4704                 cli_set_error(cli, status);
4705         }
4706         return status;
4707 }
4708
4709 /****************************************************************************
4710  unlink or rmdir - POSIX semantics.
4711 ****************************************************************************/
4712
4713 struct unlink_state {
4714         uint16_t setup;
4715         uint8_t data[2];
4716 };
4717
4718 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
4719 {
4720         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
4721                                          NULL, 0, NULL, NULL, 0, NULL);
4722         tevent_req_simple_finish_ntstatus(subreq, status);
4723 }
4724
4725 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
4726                                         struct event_context *ev,
4727                                         struct cli_state *cli,
4728                                         const char *fname,
4729                                         bool is_dir)
4730 {
4731         struct tevent_req *req = NULL, *subreq = NULL;
4732         struct unlink_state *state = NULL;
4733         uint8_t *param = NULL;
4734
4735         req = tevent_req_create(mem_ctx, &state, struct unlink_state);
4736         if (req == NULL) {
4737                 return NULL;
4738         }
4739
4740         /* Setup setup word. */
4741         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4742
4743         /* Setup param array. */
4744         param = talloc_array(state, uint8_t, 6);
4745         if (tevent_req_nomem(param, req)) {
4746                 return tevent_req_post(req, ev);
4747         }
4748         memset(param, '\0', 6);
4749         SSVAL(param, 0, SMB_POSIX_PATH_UNLINK);
4750
4751         param = trans2_bytes_push_str(param, cli_ucs2(cli), fname,
4752                                    strlen(fname)+1, NULL);
4753
4754         if (tevent_req_nomem(param, req)) {
4755                 return tevent_req_post(req, ev);
4756         }
4757
4758         /* Setup data word. */
4759         SSVAL(state->data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET :
4760                         SMB_POSIX_UNLINK_FILE_TARGET);
4761
4762         subreq = cli_trans_send(state,                  /* mem ctx. */
4763                                 ev,                     /* event ctx. */
4764                                 cli,                    /* cli_state. */
4765                                 SMBtrans2,              /* cmd. */
4766                                 NULL,                   /* pipe name. */
4767                                 -1,                     /* fid. */
4768                                 0,                      /* function. */
4769                                 0,                      /* flags. */
4770                                 &state->setup,          /* setup. */
4771                                 1,                      /* num setup uint16_t words. */
4772                                 0,                      /* max returned setup. */
4773                                 param,                  /* param. */
4774                                 talloc_get_size(param), /* num param. */
4775                                 2,                      /* max returned param. */
4776                                 state->data,            /* data. */
4777                                 2,                      /* num data. */
4778                                 0);                     /* max returned data. */
4779
4780         if (tevent_req_nomem(subreq, req)) {
4781                 return tevent_req_post(req, ev);
4782         }
4783         tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
4784         return req;
4785 }
4786
4787 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
4788                                         struct event_context *ev,
4789                                         struct cli_state *cli,
4790                                         const char *fname)
4791 {
4792         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, false);
4793 }
4794
4795 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
4796 {
4797         NTSTATUS status;
4798
4799         if (tevent_req_is_nterror(req, &status)) {
4800                 return status;
4801         }
4802         return NT_STATUS_OK;
4803 }
4804
4805 /****************************************************************************
4806  unlink - POSIX semantics.
4807 ****************************************************************************/
4808
4809 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
4810 {
4811         TALLOC_CTX *frame = talloc_stackframe();
4812         struct event_context *ev = NULL;
4813         struct tevent_req *req = NULL;
4814         NTSTATUS status = NT_STATUS_OK;
4815
4816         if (cli_has_async_calls(cli)) {
4817                 /*
4818                  * Can't use sync call while an async call is in flight
4819                  */
4820                 status = NT_STATUS_INVALID_PARAMETER;
4821                 goto fail;
4822         }
4823
4824         ev = event_context_init(frame);
4825         if (ev == NULL) {
4826                 status = NT_STATUS_NO_MEMORY;
4827                 goto fail;
4828         }
4829
4830         req = cli_posix_unlink_send(frame,
4831                                 ev,
4832                                 cli,
4833                                 fname);
4834         if (req == NULL) {
4835                 status = NT_STATUS_NO_MEMORY;
4836                 goto fail;
4837         }
4838
4839         if (!tevent_req_poll(req, ev)) {
4840                 status = map_nt_error_from_unix(errno);
4841                 goto fail;
4842         }
4843
4844         status = cli_posix_unlink_recv(req);
4845
4846  fail:
4847         TALLOC_FREE(frame);
4848         if (!NT_STATUS_IS_OK(status)) {
4849                 cli_set_error(cli, status);
4850         }
4851         return status;
4852 }
4853
4854 /****************************************************************************
4855  rmdir - POSIX semantics.
4856 ****************************************************************************/
4857
4858 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
4859                                         struct event_context *ev,
4860                                         struct cli_state *cli,
4861                                         const char *fname)
4862 {
4863         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, true);
4864 }
4865
4866 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
4867 {
4868         NTSTATUS status;
4869
4870         if (tevent_req_is_nterror(req, &status)) {
4871                 return status;
4872         }
4873         return NT_STATUS_OK;
4874 }
4875
4876 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
4877 {
4878         TALLOC_CTX *frame = talloc_stackframe();
4879         struct event_context *ev = NULL;
4880         struct tevent_req *req = NULL;
4881         NTSTATUS status = NT_STATUS_OK;
4882
4883         if (cli_has_async_calls(cli)) {
4884                 /*
4885                  * Can't use sync call while an async call is in flight
4886                  */
4887                 status = NT_STATUS_INVALID_PARAMETER;
4888                 goto fail;
4889         }
4890
4891         ev = event_context_init(frame);
4892         if (ev == NULL) {
4893                 status = NT_STATUS_NO_MEMORY;
4894                 goto fail;
4895         }
4896
4897         req = cli_posix_rmdir_send(frame,
4898                                 ev,
4899                                 cli,
4900                                 fname);
4901         if (req == NULL) {
4902                 status = NT_STATUS_NO_MEMORY;
4903                 goto fail;
4904         }
4905
4906         if (!tevent_req_poll(req, ev)) {
4907                 status = map_nt_error_from_unix(errno);
4908                 goto fail;
4909         }
4910
4911         status = cli_posix_rmdir_recv(req, frame);
4912
4913  fail:
4914         TALLOC_FREE(frame);
4915         if (!NT_STATUS_IS_OK(status)) {
4916                 cli_set_error(cli, status);
4917         }
4918         return status;
4919 }
4920
4921 /****************************************************************************
4922  filechangenotify
4923 ****************************************************************************/
4924
4925 struct cli_notify_state {
4926         uint8_t setup[8];
4927         uint32_t num_changes;
4928         struct notify_change *changes;
4929 };
4930
4931 static void cli_notify_done(struct tevent_req *subreq);
4932
4933 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
4934                                    struct tevent_context *ev,
4935                                    struct cli_state *cli, uint16_t fnum,
4936                                    uint32_t buffer_size,
4937                                    uint32_t completion_filter, bool recursive)
4938 {
4939         struct tevent_req *req, *subreq;
4940         struct cli_notify_state *state;
4941
4942         req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
4943         if (req == NULL) {
4944                 return NULL;
4945         }
4946
4947         SIVAL(state->setup, 0, completion_filter);
4948         SSVAL(state->setup, 4, fnum);
4949         SSVAL(state->setup, 6, recursive);
4950
4951         subreq = cli_trans_send(
4952                 state,                  /* mem ctx. */
4953                 ev,                     /* event ctx. */
4954                 cli,                    /* cli_state. */
4955                 SMBnttrans,             /* cmd. */
4956                 NULL,                   /* pipe name. */
4957                 -1,                     /* fid. */
4958                 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
4959                 0,                      /* flags. */
4960                 (uint16_t *)state->setup, /* setup. */
4961                 4,                      /* num setup uint16_t words. */
4962                 0,                      /* max returned setup. */
4963                 NULL,                   /* param. */
4964                 0,                      /* num param. */
4965                 buffer_size,            /* max returned param. */
4966                 NULL,                   /* data. */
4967                 0,                      /* num data. */
4968                 0);                     /* max returned data. */
4969
4970         if (tevent_req_nomem(subreq, req)) {
4971                 return tevent_req_post(req, ev);
4972         }
4973         tevent_req_set_callback(subreq, cli_notify_done, req);
4974         return req;
4975 }
4976
4977 static void cli_notify_done(struct tevent_req *subreq)
4978 {
4979         struct tevent_req *req = tevent_req_callback_data(
4980                 subreq, struct tevent_req);
4981         struct cli_notify_state *state = tevent_req_data(
4982                 req, struct cli_notify_state);
4983         NTSTATUS status;
4984         uint8_t *params;
4985         uint32_t i, ofs, num_params;
4986         uint16_t flags2;
4987
4988         status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
4989                                 &params, 0, &num_params, NULL, 0, NULL);
4990         TALLOC_FREE(subreq);
4991         if (!NT_STATUS_IS_OK(status)) {
4992                 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
4993                 tevent_req_nterror(req, status);
4994                 return;
4995         }
4996
4997         state->num_changes = 0;
4998         ofs = 0;
4999
5000         while (num_params - ofs > 12) {
5001                 uint32_t len = IVAL(params, ofs);
5002                 state->num_changes += 1;
5003
5004                 if ((len == 0) || (ofs+len >= num_params)) {
5005                         break;
5006                 }
5007                 ofs += len;
5008         }
5009
5010         state->changes = talloc_array(state, struct notify_change,
5011                                       state->num_changes);
5012         if (tevent_req_nomem(state->changes, req)) {
5013                 TALLOC_FREE(params);
5014                 return;
5015         }
5016
5017         ofs = 0;
5018
5019         for (i=0; i<state->num_changes; i++) {
5020                 uint32_t next = IVAL(params, ofs);
5021                 uint32_t len = IVAL(params, ofs+8);
5022                 ssize_t ret;
5023                 char *name;
5024
5025                 if ((next != 0) && (len+12 != next)) {
5026                         TALLOC_FREE(params);
5027                         tevent_req_nterror(
5028                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5029                         return;
5030                 }
5031
5032                 state->changes[i].action = IVAL(params, ofs+4);
5033                 ret = clistr_pull_talloc(params, (char *)params, flags2,
5034                                          &name, params+ofs+12, len,
5035                                          STR_TERMINATE|STR_UNICODE);
5036                 if (ret == -1) {
5037                         TALLOC_FREE(params);
5038                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5039                         return;
5040                 }
5041                 state->changes[i].name = name;
5042                 ofs += next;
5043         }
5044
5045         TALLOC_FREE(params);
5046         tevent_req_done(req);
5047 }
5048
5049 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5050                          uint32_t *pnum_changes,
5051                          struct notify_change **pchanges)
5052 {
5053         struct cli_notify_state *state = tevent_req_data(
5054                 req, struct cli_notify_state);
5055         NTSTATUS status;
5056
5057         if (tevent_req_is_nterror(req, &status)) {
5058                 return status;
5059         }
5060
5061         *pnum_changes = state->num_changes;
5062         *pchanges = talloc_move(mem_ctx, &state->changes);
5063         return NT_STATUS_OK;
5064 }
5065
5066 struct cli_qpathinfo_state {
5067         uint8_t *param;
5068         uint8_t *data;
5069         uint16_t setup[1];
5070         uint32_t min_rdata;
5071         uint8_t *rdata;
5072         uint32_t num_rdata;
5073 };
5074
5075 static void cli_qpathinfo_done(struct tevent_req *subreq);
5076
5077 struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
5078                                       struct tevent_context *ev,
5079                                       struct cli_state *cli, const char *fname,
5080                                       uint16_t level, uint32_t min_rdata,
5081                                       uint32_t max_rdata)
5082 {
5083         struct tevent_req *req, *subreq;
5084         struct cli_qpathinfo_state *state;
5085
5086         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
5087         if (req == NULL) {
5088                 return NULL;
5089         }
5090         state->min_rdata = min_rdata;
5091         SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
5092
5093         state->param = talloc_zero_array(state, uint8_t, 6);
5094         if (tevent_req_nomem(state->param, req)) {
5095                 return tevent_req_post(req, ev);
5096         }
5097         SSVAL(state->param, 0, level);
5098         state->param = trans2_bytes_push_str(
5099                 state->param, cli_ucs2(cli), fname, strlen(fname)+1, NULL);
5100         if (tevent_req_nomem(state->param, req)) {
5101                 return tevent_req_post(req, ev);
5102         }
5103
5104         subreq = cli_trans_send(
5105                 state,                  /* mem ctx. */
5106                 ev,                     /* event ctx. */
5107                 cli,                    /* cli_state. */
5108                 SMBtrans2,              /* cmd. */
5109                 NULL,                   /* pipe name. */
5110                 -1,                     /* fid. */
5111                 0,                      /* function. */
5112                 0,                      /* flags. */
5113                 state->setup,           /* setup. */
5114                 1,                      /* num setup uint16_t words. */
5115                 0,                      /* max returned setup. */
5116                 state->param,           /* param. */
5117                 talloc_get_size(state->param),  /* num param. */
5118                 2,                      /* max returned param. */
5119                 NULL,                   /* data. */
5120                 0,                      /* num data. */
5121                 max_rdata);             /* max returned data. */
5122
5123         if (tevent_req_nomem(subreq, req)) {
5124                 return tevent_req_post(req, ev);
5125         }
5126         tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
5127         return req;
5128 }
5129
5130 static void cli_qpathinfo_done(struct tevent_req *subreq)
5131 {
5132         struct tevent_req *req = tevent_req_callback_data(
5133                 subreq, struct tevent_req);
5134         struct cli_qpathinfo_state *state = tevent_req_data(
5135                 req, struct cli_qpathinfo_state);
5136         NTSTATUS status;
5137
5138         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5139                                 NULL, 0, NULL,
5140                                 &state->rdata, state->min_rdata,
5141                                 &state->num_rdata);
5142         if (!NT_STATUS_IS_OK(status)) {
5143                 tevent_req_nterror(req, status);
5144                 return;
5145         }
5146         tevent_req_done(req);
5147 }
5148
5149 NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5150                             uint8_t **rdata, uint32_t *num_rdata)
5151 {
5152         struct cli_qpathinfo_state *state = tevent_req_data(
5153                 req, struct cli_qpathinfo_state);
5154         NTSTATUS status;
5155
5156         if (tevent_req_is_nterror(req, &status)) {
5157                 return status;
5158         }
5159         if (rdata != NULL) {
5160                 *rdata = talloc_move(mem_ctx, &state->rdata);
5161         } else {
5162                 TALLOC_FREE(state->rdata);
5163         }
5164         if (num_rdata != NULL) {
5165                 *num_rdata = state->num_rdata;
5166         }
5167         return NT_STATUS_OK;
5168 }
5169
5170 NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5171                        const char *fname, uint16_t level, uint32_t min_rdata,
5172                        uint32_t max_rdata,
5173                        uint8_t **rdata, uint32_t *num_rdata)
5174 {
5175         TALLOC_CTX *frame = talloc_stackframe();
5176         struct event_context *ev;
5177         struct tevent_req *req;
5178         NTSTATUS status = NT_STATUS_NO_MEMORY;
5179
5180         if (cli_has_async_calls(cli)) {
5181                 /*
5182                  * Can't use sync call while an async call is in flight
5183                  */
5184                 status = NT_STATUS_INVALID_PARAMETER;
5185                 goto fail;
5186         }
5187         ev = event_context_init(frame);
5188         if (ev == NULL) {
5189                 goto fail;
5190         }
5191         req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
5192                                  max_rdata);
5193         if (req == NULL) {
5194                 goto fail;
5195         }
5196         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5197                 goto fail;
5198         }
5199         status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
5200  fail:
5201         TALLOC_FREE(frame);
5202         if (!NT_STATUS_IS_OK(status)) {
5203                 cli_set_error(cli, status);
5204         }
5205         return status;
5206 }
5207
5208 struct cli_qfileinfo_state {
5209         uint16_t setup[1];
5210         uint8_t param[4];
5211         uint8_t *data;
5212         uint32_t min_rdata;
5213         uint8_t *rdata;
5214         uint32_t num_rdata;
5215 };
5216
5217 static void cli_qfileinfo_done(struct tevent_req *subreq);
5218
5219 struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
5220                                       struct tevent_context *ev,
5221                                       struct cli_state *cli, uint16_t fnum,
5222                                       uint16_t level, uint32_t min_rdata,
5223                                       uint32_t max_rdata)
5224 {
5225         struct tevent_req *req, *subreq;
5226         struct cli_qfileinfo_state *state;
5227
5228         req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
5229         if (req == NULL) {
5230                 return NULL;
5231         }
5232         state->min_rdata = min_rdata;
5233         SSVAL(state->param, 0, fnum);
5234         SSVAL(state->param, 2, level);
5235         SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
5236
5237         subreq = cli_trans_send(
5238                 state,                  /* mem ctx. */
5239                 ev,                     /* event ctx. */
5240                 cli,                    /* cli_state. */
5241                 SMBtrans2,              /* cmd. */
5242                 NULL,                   /* pipe name. */
5243                 -1,                     /* fid. */
5244                 0,                      /* function. */
5245                 0,                      /* flags. */
5246                 state->setup,           /* setup. */
5247                 1,                      /* num setup uint16_t words. */
5248                 0,                      /* max returned setup. */
5249                 state->param,           /* param. */
5250                 sizeof(state->param),   /* num param. */
5251                 2,                      /* max returned param. */
5252                 NULL,                   /* data. */
5253                 0,                      /* num data. */
5254                 max_rdata);             /* max returned data. */
5255
5256         if (tevent_req_nomem(subreq, req)) {
5257                 return tevent_req_post(req, ev);
5258         }
5259         tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
5260         return req;
5261 }
5262
5263 static void cli_qfileinfo_done(struct tevent_req *subreq)
5264 {
5265         struct tevent_req *req = tevent_req_callback_data(
5266                 subreq, struct tevent_req);
5267         struct cli_qfileinfo_state *state = tevent_req_data(
5268                 req, struct cli_qfileinfo_state);
5269         NTSTATUS status;
5270
5271         status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
5272                                 NULL, 0, NULL,
5273                                 &state->rdata, state->min_rdata,
5274                                 &state->num_rdata);
5275         if (!NT_STATUS_IS_OK(status)) {
5276                 tevent_req_nterror(req, status);
5277                 return;
5278         }
5279         tevent_req_done(req);
5280 }
5281
5282 NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5283                             uint8_t **rdata, uint32_t *num_rdata)
5284 {
5285         struct cli_qfileinfo_state *state = tevent_req_data(
5286                 req, struct cli_qfileinfo_state);
5287         NTSTATUS status;
5288
5289         if (tevent_req_is_nterror(req, &status)) {
5290                 return status;
5291         }
5292         if (rdata != NULL) {
5293                 *rdata = talloc_move(mem_ctx, &state->rdata);
5294         } else {
5295                 TALLOC_FREE(state->rdata);
5296         }
5297         if (num_rdata != NULL) {
5298                 *num_rdata = state->num_rdata;
5299         }
5300         return NT_STATUS_OK;
5301 }
5302
5303 NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
5304                        uint16_t fnum, uint16_t level, uint32_t min_rdata,
5305                        uint32_t max_rdata,
5306                        uint8_t **rdata, uint32_t *num_rdata)
5307 {
5308         TALLOC_CTX *frame = talloc_stackframe();
5309         struct event_context *ev;
5310         struct tevent_req *req;
5311         NTSTATUS status = NT_STATUS_NO_MEMORY;
5312
5313         if (cli_has_async_calls(cli)) {
5314                 /*
5315                  * Can't use sync call while an async call is in flight
5316                  */
5317                 status = NT_STATUS_INVALID_PARAMETER;
5318                 goto fail;
5319         }
5320         ev = event_context_init(frame);
5321         if (ev == NULL) {
5322                 goto fail;
5323         }
5324         req = cli_qfileinfo_send(frame, ev, cli, fnum, level, min_rdata,
5325                                  max_rdata);
5326         if (req == NULL) {
5327                 goto fail;
5328         }
5329         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5330                 goto fail;
5331         }
5332         status = cli_qfileinfo_recv(req, mem_ctx, rdata, num_rdata);
5333  fail:
5334         TALLOC_FREE(frame);
5335         if (!NT_STATUS_IS_OK(status)) {
5336                 cli_set_error(cli, status);
5337         }
5338         return status;
5339 }
5340
5341 struct cli_flush_state {
5342         uint16_t vwv[1];
5343 };
5344
5345 static void cli_flush_done(struct tevent_req *subreq);
5346
5347 struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
5348                                   struct event_context *ev,
5349                                   struct cli_state *cli,
5350                                   uint16_t fnum)
5351 {
5352         struct tevent_req *req, *subreq;
5353         struct cli_flush_state *state;
5354
5355         req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
5356         if (req == NULL) {
5357                 return NULL;
5358         }
5359         SSVAL(state->vwv + 0, 0, fnum);
5360
5361         subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 1, state->vwv,
5362                               0, NULL);
5363         if (tevent_req_nomem(subreq, req)) {
5364                 return tevent_req_post(req, ev);
5365         }
5366         tevent_req_set_callback(subreq, cli_flush_done, req);
5367         return req;
5368 }
5369
5370 static void cli_flush_done(struct tevent_req *subreq)
5371 {
5372         struct tevent_req *req = tevent_req_callback_data(
5373                 subreq, struct tevent_req);
5374         NTSTATUS status;
5375
5376         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5377         TALLOC_FREE(subreq);
5378         if (!NT_STATUS_IS_OK(status)) {
5379                 tevent_req_nterror(req, status);
5380                 return;
5381         }
5382         tevent_req_done(req);
5383 }
5384
5385 NTSTATUS cli_flush_recv(struct tevent_req *req)
5386 {
5387         return tevent_req_simple_recv_ntstatus(req);
5388 }
5389
5390 NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
5391 {
5392         TALLOC_CTX *frame = talloc_stackframe();
5393         struct event_context *ev;
5394         struct tevent_req *req;
5395         NTSTATUS status = NT_STATUS_NO_MEMORY;
5396
5397         if (cli_has_async_calls(cli)) {
5398                 /*
5399                  * Can't use sync call while an async call is in flight
5400                  */
5401                 status = NT_STATUS_INVALID_PARAMETER;
5402                 goto fail;
5403         }
5404         ev = event_context_init(frame);
5405         if (ev == NULL) {
5406                 goto fail;
5407         }
5408         req = cli_flush_send(frame, ev, cli, fnum);
5409         if (req == NULL) {
5410                 goto fail;
5411         }
5412         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5413                 goto fail;
5414         }
5415         status = cli_flush_recv(req);
5416  fail:
5417         TALLOC_FREE(frame);
5418         if (!NT_STATUS_IS_OK(status)) {
5419                 cli_set_error(cli, status);
5420         }
5421         return status;
5422 }