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