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