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