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