ec81cf92019b7e26a27fc1502dda1c8a1bcb991a
[samba.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 /***********************************************************
24  Common function for pushing stings, used by smb_bytes_push_str()
25  and trans_bytes_push_str(). Only difference is the align_odd
26  parameter setting.
27 ***********************************************************/
28
29 static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
30                                 const char *str, size_t str_len,
31                                 bool align_odd,
32                                 size_t *pconverted_size)
33 {
34         size_t buflen;
35         char *converted;
36         size_t converted_size;
37
38         if (buf == NULL) {
39                 return NULL;
40         }
41
42         buflen = talloc_get_size(buf);
43
44         if (align_odd && ucs2 && (buflen % 2 == 0)) {
45                 /*
46                  * We're pushing into an SMB buffer, align odd
47                  */
48                 buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
49                 if (buf == NULL) {
50                         return NULL;
51                 }
52                 buf[buflen] = '\0';
53                 buflen += 1;
54         }
55
56         if (!convert_string_talloc(talloc_tos(), CH_UNIX,
57                                    ucs2 ? CH_UTF16LE : CH_DOS,
58                                    str, str_len, &converted,
59                                    &converted_size, true)) {
60                 return NULL;
61         }
62
63         buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
64                                    buflen + converted_size);
65         if (buf == NULL) {
66                 TALLOC_FREE(converted);
67                 return NULL;
68         }
69
70         memcpy(buf + buflen, converted, converted_size);
71
72         TALLOC_FREE(converted);
73
74         if (pconverted_size) {
75                 *pconverted_size = converted_size;
76         }
77
78         return buf;
79 }
80
81 /***********************************************************
82  Push a string into an SMB buffer, with odd byte alignment
83  if it's a UCS2 string.
84 ***********************************************************/
85
86 uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
87                             const char *str, size_t str_len,
88                             size_t *pconverted_size)
89 {
90         return internal_bytes_push_str(buf, ucs2, str, str_len,
91                         true, pconverted_size);
92 }
93
94 /***********************************************************
95  Same as smb_bytes_push_str(), but without the odd byte
96  align for ucs2 (we're pushing into a param or data block).
97  static for now, although this will probably change when
98  other modules use async trans calls.
99 ***********************************************************/
100
101 static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
102                             const char *str, size_t str_len,
103                             size_t *pconverted_size)
104 {
105         return internal_bytes_push_str(buf, ucs2, str, str_len,
106                         false, pconverted_size);
107 }
108
109 /****************************************************************************
110  Hard/Symlink a file (UNIX extensions).
111  Creates new name (sym)linked to oldname.
112 ****************************************************************************/
113
114 struct link_state {
115         uint16_t setup;
116         uint8_t *param;
117         uint8_t *data;
118 };
119
120 static void cli_posix_link_internal_done(struct tevent_req *subreq)
121 {
122         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
123                                          NULL, 0, NULL, NULL, 0, NULL);
124         tevent_req_simple_finish_ntstatus(subreq, status);
125 }
126
127 static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
128                                         struct event_context *ev,
129                                         struct cli_state *cli,
130                                         const char *oldname,
131                                         const char *newname,
132                                         bool hardlink)
133 {
134         struct tevent_req *req = NULL, *subreq = NULL;
135         struct link_state *state = NULL;
136
137         req = tevent_req_create(mem_ctx, &state, struct link_state);
138         if (req == NULL) {
139                 return NULL;
140         }
141
142         /* Setup setup word. */
143         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
144
145         /* Setup param array. */
146         state->param = talloc_array(state, uint8_t, 6);
147         if (tevent_req_nomem(state->param, req)) {
148                 return tevent_req_post(req, ev);
149         }
150         memset(state->param, '\0', 6);
151         SSVAL(state->param,0,hardlink ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
152
153         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), newname,
154                                    strlen(newname)+1, NULL);
155
156         if (tevent_req_nomem(state->param, req)) {
157                 return tevent_req_post(req, ev);
158         }
159
160         /* Setup data array. */
161         state->data = talloc_array(state, uint8_t, 0);
162         if (tevent_req_nomem(state->data, req)) {
163                 return tevent_req_post(req, ev);
164         }
165         state->data = trans2_bytes_push_str(state->data, cli_ucs2(cli), oldname,
166                                    strlen(oldname)+1, NULL);
167
168         subreq = cli_trans_send(state,                  /* mem ctx. */
169                                 ev,                     /* event ctx. */
170                                 cli,                    /* cli_state. */
171                                 SMBtrans2,              /* cmd. */
172                                 NULL,                   /* pipe name. */
173                                 -1,                     /* fid. */
174                                 0,                      /* function. */
175                                 0,                      /* flags. */
176                                 &state->setup,          /* setup. */
177                                 1,                      /* num setup uint16_t words. */
178                                 0,                      /* max returned setup. */
179                                 state->param,           /* param. */
180                                 talloc_get_size(state->param),  /* num param. */
181                                 2,                      /* max returned param. */
182                                 state->data,            /* data. */
183                                 talloc_get_size(state->data),   /* num data. */
184                                 0);                     /* max returned data. */
185
186         if (tevent_req_nomem(subreq, req)) {
187                 return tevent_req_post(req, ev);
188         }
189         tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
190         return req;
191 }
192
193 /****************************************************************************
194  Symlink a file (UNIX extensions).
195 ****************************************************************************/
196
197 struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
198                                         struct event_context *ev,
199                                         struct cli_state *cli,
200                                         const char *oldname,
201                                         const char *newname)
202 {
203         return cli_posix_link_internal_send(mem_ctx, ev, cli,
204                         oldname, newname, false);
205 }
206
207 NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
208 {
209         NTSTATUS status;
210
211         if (tevent_req_is_nterror(req, &status)) {
212                 return status;
213         }
214         return NT_STATUS_OK;
215 }
216
217 NTSTATUS cli_posix_symlink(struct cli_state *cli,
218                         const char *oldname,
219                         const char *newname)
220 {
221         TALLOC_CTX *frame = talloc_stackframe();
222         struct event_context *ev = NULL;
223         struct tevent_req *req = NULL;
224         NTSTATUS status = NT_STATUS_OK;
225
226         if (cli_has_async_calls(cli)) {
227                 /*
228                  * Can't use sync call while an async call is in flight
229                  */
230                 status = NT_STATUS_INVALID_PARAMETER;
231                 goto fail;
232         }
233
234         ev = event_context_init(frame);
235         if (ev == NULL) {
236                 status = NT_STATUS_NO_MEMORY;
237                 goto fail;
238         }
239
240         req = cli_posix_symlink_send(frame,
241                                 ev,
242                                 cli,
243                                 oldname,
244                                 newname);
245         if (req == NULL) {
246                 status = NT_STATUS_NO_MEMORY;
247                 goto fail;
248         }
249
250         if (!tevent_req_poll(req, ev)) {
251                 status = map_nt_error_from_unix(errno);
252                 goto fail;
253         }
254
255         status = cli_posix_symlink_recv(req);
256
257  fail:
258         TALLOC_FREE(frame);
259         if (!NT_STATUS_IS_OK(status)) {
260                 cli_set_error(cli, status);
261         }
262         return status;
263 }
264
265 /****************************************************************************
266  Read a POSIX symlink.
267 ****************************************************************************/
268
269 struct readlink_state {
270         uint16_t setup;
271         uint8_t *param;
272         uint8_t *data;
273         uint32_t num_data;
274 };
275
276 static void cli_posix_readlink_done(struct tevent_req *subreq)
277 {
278         struct tevent_req *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         uint8_t *inbuf;
3435         NTSTATUS status;
3436
3437         status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3438                               NULL);
3439         TALLOC_FREE(subreq);
3440         if (!NT_STATUS_IS_OK(status)) {
3441                 tevent_req_nterror(req, status);
3442                 return;
3443         }
3444
3445         state->attr = SVAL(vwv+0,0);
3446         state->size = (SMB_OFF_T)IVAL(vwv+3,0);
3447         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3448
3449         tevent_req_done(req);
3450 }
3451
3452 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3453                         uint16_t *attr,
3454                         SMB_OFF_T *size,
3455                         time_t *write_time)
3456 {
3457         struct cli_getatr_state *state = tevent_req_data(
3458                                 req, struct cli_getatr_state);
3459         NTSTATUS status;
3460
3461         if (tevent_req_is_nterror(req, &status)) {
3462                 return status;
3463         }
3464         if (attr) {
3465                 *attr = state->attr;
3466         }
3467         if (size) {
3468                 *size = state->size;
3469         }
3470         if (write_time) {
3471                 *write_time = state->write_time;
3472         }
3473         return NT_STATUS_OK;
3474 }
3475
3476 NTSTATUS cli_getatr(struct cli_state *cli,
3477                         const char *fname,
3478                         uint16_t *attr,
3479                         SMB_OFF_T *size,
3480                         time_t *write_time)
3481 {
3482         TALLOC_CTX *frame = talloc_stackframe();
3483         struct event_context *ev = NULL;
3484         struct tevent_req *req = NULL;
3485         NTSTATUS status = NT_STATUS_OK;
3486
3487         if (cli_has_async_calls(cli)) {
3488                 /*
3489                  * Can't use sync call while an async call is in flight
3490                  */
3491                 status = NT_STATUS_INVALID_PARAMETER;
3492                 goto fail;
3493         }
3494
3495         ev = event_context_init(frame);
3496         if (ev == NULL) {
3497                 status = NT_STATUS_NO_MEMORY;
3498                 goto fail;
3499         }
3500
3501         req = cli_getatr_send(frame, ev, cli, fname);
3502         if (req == NULL) {
3503                 status = NT_STATUS_NO_MEMORY;
3504                 goto fail;
3505         }
3506
3507         if (!tevent_req_poll(req, ev)) {
3508                 status = map_nt_error_from_unix(errno);
3509                 goto fail;
3510         }
3511
3512         status = cli_getatr_recv(req,
3513                                 attr,
3514                                 size,
3515                                 write_time);
3516
3517  fail:
3518         TALLOC_FREE(frame);
3519         if (!NT_STATUS_IS_OK(status)) {
3520                 cli_set_error(cli, status);
3521         }
3522         return status;
3523 }
3524
3525 /****************************************************************************
3526  Do a SMBsetattrE call.
3527 ****************************************************************************/
3528
3529 static void cli_setattrE_done(struct tevent_req *subreq);
3530
3531 struct cli_setattrE_state {
3532         uint16_t vwv[7];
3533 };
3534
3535 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3536                                 struct event_context *ev,
3537                                 struct cli_state *cli,
3538                                 uint16_t fnum,
3539                                 time_t change_time,
3540                                 time_t access_time,
3541                                 time_t write_time)
3542 {
3543         struct tevent_req *req = NULL, *subreq = NULL;
3544         struct cli_setattrE_state *state = NULL;
3545         uint8_t additional_flags = 0;
3546
3547         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3548         if (req == NULL) {
3549                 return NULL;
3550         }
3551
3552         SSVAL(state->vwv+0, 0, fnum);
3553         cli_put_dos_date2(cli, (char *)&state->vwv[1], 0, change_time);
3554         cli_put_dos_date2(cli, (char *)&state->vwv[3], 0, access_time);
3555         cli_put_dos_date2(cli, (char *)&state->vwv[5], 0, write_time);
3556
3557         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3558                               7, state->vwv, 0, NULL);
3559         if (tevent_req_nomem(subreq, req)) {
3560                 return tevent_req_post(req, ev);
3561         }
3562         tevent_req_set_callback(subreq, cli_setattrE_done, req);
3563         return req;
3564 }
3565
3566 static void cli_setattrE_done(struct tevent_req *subreq)
3567 {
3568         struct tevent_req *req = tevent_req_callback_data(
3569                 subreq, struct tevent_req);
3570         NTSTATUS status;
3571
3572         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3573         TALLOC_FREE(subreq);
3574         if (!NT_STATUS_IS_OK(status)) {
3575                 tevent_req_nterror(req, status);
3576                 return;
3577         }
3578         tevent_req_done(req);
3579 }
3580
3581 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3582 {
3583         return tevent_req_simple_recv_ntstatus(req);
3584 }
3585
3586 NTSTATUS cli_setattrE(struct cli_state *cli,
3587                         uint16_t fnum,
3588                         time_t change_time,
3589                         time_t access_time,
3590                         time_t write_time)
3591 {
3592         TALLOC_CTX *frame = talloc_stackframe();
3593         struct event_context *ev = NULL;
3594         struct tevent_req *req = NULL;
3595         NTSTATUS status = NT_STATUS_OK;
3596
3597         if (cli_has_async_calls(cli)) {
3598                 /*
3599                  * Can't use sync call while an async call is in flight
3600                  */
3601                 status = NT_STATUS_INVALID_PARAMETER;
3602                 goto fail;
3603         }
3604
3605         ev = event_context_init(frame);
3606         if (ev == NULL) {
3607                 status = NT_STATUS_NO_MEMORY;
3608                 goto fail;
3609         }
3610
3611         req = cli_setattrE_send(frame, ev,
3612                         cli,
3613                         fnum,
3614                         change_time,
3615                         access_time,
3616                         write_time);
3617
3618         if (req == NULL) {
3619                 status = NT_STATUS_NO_MEMORY;
3620                 goto fail;
3621         }
3622
3623         if (!tevent_req_poll(req, ev)) {
3624                 status = map_nt_error_from_unix(errno);
3625                 goto fail;
3626         }
3627
3628         status = cli_setattrE_recv(req);
3629
3630  fail:
3631         TALLOC_FREE(frame);
3632         if (!NT_STATUS_IS_OK(status)) {
3633                 cli_set_error(cli, status);
3634         }
3635         return status;
3636 }
3637
3638 /****************************************************************************
3639  Do a SMBsetatr call.
3640 ****************************************************************************/
3641
3642 static void cli_setatr_done(struct tevent_req *subreq);
3643
3644 struct cli_setatr_state {
3645         uint16_t vwv[8];
3646 };
3647
3648 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
3649                                 struct event_context *ev,
3650                                 struct cli_state *cli,
3651                                 const char *fname,
3652                                 uint16_t attr,
3653                                 time_t mtime)
3654 {
3655         struct tevent_req *req = NULL, *subreq = NULL;
3656         struct cli_setatr_state *state = NULL;
3657         uint8_t additional_flags = 0;
3658         uint8_t *bytes = NULL;
3659
3660         req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
3661         if (req == NULL) {
3662                 return NULL;
3663         }
3664
3665         SSVAL(state->vwv+0, 0, attr);
3666         cli_put_dos_date3(cli, (char *)&state->vwv[1], 0, mtime);
3667
3668         bytes = talloc_array(state, uint8_t, 1);
3669         if (tevent_req_nomem(bytes, req)) {
3670                 return tevent_req_post(req, ev);
3671         }
3672         bytes[0] = 4;
3673         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3674                                    strlen(fname)+1, NULL);
3675         if (tevent_req_nomem(bytes, req)) {
3676                 return tevent_req_post(req, ev);
3677         }
3678         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
3679                         talloc_get_size(bytes)+1);
3680         if (tevent_req_nomem(bytes, req)) {
3681                 return tevent_req_post(req, ev);
3682         }
3683
3684         bytes[talloc_get_size(bytes)-1] = 4;
3685         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",
3686                                    1, NULL);
3687         if (tevent_req_nomem(bytes, req)) {
3688                 return tevent_req_post(req, ev);
3689         }
3690
3691         subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
3692                               8, state->vwv, talloc_get_size(bytes), bytes);
3693         if (tevent_req_nomem(subreq, req)) {
3694                 return tevent_req_post(req, ev);
3695         }
3696         tevent_req_set_callback(subreq, cli_setatr_done, req);
3697         return req;
3698 }
3699
3700 static void cli_setatr_done(struct tevent_req *subreq)
3701 {
3702         struct tevent_req *req = tevent_req_callback_data(
3703                 subreq, struct tevent_req);
3704         NTSTATUS status;
3705
3706         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3707         TALLOC_FREE(subreq);
3708         if (!NT_STATUS_IS_OK(status)) {
3709                 tevent_req_nterror(req, status);
3710                 return;
3711         }
3712         tevent_req_done(req);
3713 }
3714
3715 NTSTATUS cli_setatr_recv(struct tevent_req *req)
3716 {
3717         return tevent_req_simple_recv_ntstatus(req);
3718 }
3719
3720 NTSTATUS cli_setatr(struct cli_state *cli,
3721                 const char *fname,
3722                 uint16_t attr,
3723                 time_t mtime)
3724 {
3725         TALLOC_CTX *frame = talloc_stackframe();
3726         struct event_context *ev = NULL;
3727         struct tevent_req *req = NULL;
3728         NTSTATUS status = NT_STATUS_OK;
3729
3730         if (cli_has_async_calls(cli)) {
3731                 /*
3732                  * Can't use sync call while an async call is in flight
3733                  */
3734                 status = NT_STATUS_INVALID_PARAMETER;
3735                 goto fail;
3736         }
3737
3738         ev = event_context_init(frame);
3739         if (ev == NULL) {
3740                 status = NT_STATUS_NO_MEMORY;
3741                 goto fail;
3742         }
3743
3744         req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
3745         if (req == NULL) {
3746                 status = NT_STATUS_NO_MEMORY;
3747                 goto fail;
3748         }
3749
3750         if (!tevent_req_poll(req, ev)) {
3751                 status = map_nt_error_from_unix(errno);
3752                 goto fail;
3753         }
3754
3755         status = cli_setatr_recv(req);
3756
3757  fail:
3758         TALLOC_FREE(frame);
3759         if (!NT_STATUS_IS_OK(status)) {
3760                 cli_set_error(cli, status);
3761         }
3762         return status;
3763 }
3764
3765 /****************************************************************************
3766  Check for existance of a dir.
3767 ****************************************************************************/
3768
3769 static void cli_chkpath_done(struct tevent_req *subreq);
3770
3771 struct cli_chkpath_state {
3772         int dummy;
3773 };
3774
3775 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
3776                                   struct event_context *ev,
3777                                   struct cli_state *cli,
3778                                   const char *fname)
3779 {
3780         struct tevent_req *req = NULL, *subreq = NULL;
3781         struct cli_chkpath_state *state = NULL;
3782         uint8_t additional_flags = 0;
3783         uint8_t *bytes = NULL;
3784
3785         req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
3786         if (req == NULL) {
3787                 return NULL;
3788         }
3789
3790         bytes = talloc_array(state, uint8_t, 1);
3791         if (tevent_req_nomem(bytes, req)) {
3792                 return tevent_req_post(req, ev);
3793         }
3794         bytes[0] = 4;
3795         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3796                                    strlen(fname)+1, NULL);
3797
3798         if (tevent_req_nomem(bytes, req)) {
3799                 return tevent_req_post(req, ev);
3800         }
3801
3802         subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
3803                               0, NULL, talloc_get_size(bytes), bytes);
3804         if (tevent_req_nomem(subreq, req)) {
3805                 return tevent_req_post(req, ev);
3806         }
3807         tevent_req_set_callback(subreq, cli_chkpath_done, req);
3808         return req;
3809 }
3810
3811 static void cli_chkpath_done(struct tevent_req *subreq)
3812 {
3813         struct tevent_req *req = tevent_req_callback_data(
3814                 subreq, struct tevent_req);
3815         NTSTATUS status;
3816
3817         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3818         TALLOC_FREE(subreq);
3819         if (!NT_STATUS_IS_OK(status)) {
3820                 tevent_req_nterror(req, status);
3821                 return;
3822         }
3823         tevent_req_done(req);
3824 }
3825
3826 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
3827 {
3828         return tevent_req_simple_recv_ntstatus(req);
3829 }
3830
3831 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
3832 {
3833         TALLOC_CTX *frame = talloc_stackframe();
3834         struct event_context *ev = NULL;
3835         struct tevent_req *req = NULL;
3836         char *path2 = NULL;
3837         NTSTATUS status = NT_STATUS_OK;
3838
3839         if (cli_has_async_calls(cli)) {
3840                 /*
3841                  * Can't use sync call while an async call is in flight
3842                  */
3843                 status = NT_STATUS_INVALID_PARAMETER;
3844                 goto fail;
3845         }
3846
3847         path2 = talloc_strdup(frame, path);
3848         if (!path2) {
3849                 status = NT_STATUS_NO_MEMORY;
3850                 goto fail;
3851         }
3852         trim_char(path2,'\0','\\');
3853         if (!*path2) {
3854                 path2 = talloc_strdup(frame, "\\");
3855                 if (!path2) {
3856                         status = NT_STATUS_NO_MEMORY;
3857                         goto fail;
3858                 }
3859         }
3860
3861         ev = event_context_init(frame);
3862         if (ev == NULL) {
3863                 status = NT_STATUS_NO_MEMORY;
3864                 goto fail;
3865         }
3866
3867         req = cli_chkpath_send(frame, ev, cli, path2);
3868         if (req == NULL) {
3869                 status = NT_STATUS_NO_MEMORY;
3870                 goto fail;
3871         }
3872
3873         if (!tevent_req_poll(req, ev)) {
3874                 status = map_nt_error_from_unix(errno);
3875                 goto fail;
3876         }
3877
3878         status = cli_chkpath_recv(req);
3879
3880  fail:
3881         TALLOC_FREE(frame);
3882         if (!NT_STATUS_IS_OK(status)) {
3883                 cli_set_error(cli, status);
3884         }
3885         return status;
3886 }
3887
3888 /****************************************************************************
3889  Query disk space.
3890 ****************************************************************************/
3891
3892 static void cli_dskattr_done(struct tevent_req *subreq);
3893
3894 struct cli_dskattr_state {
3895         int bsize;
3896         int total;
3897         int avail;
3898 };
3899
3900 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
3901                                   struct event_context *ev,
3902                                   struct cli_state *cli)
3903 {
3904         struct tevent_req *req = NULL, *subreq = NULL;
3905         struct cli_dskattr_state *state = NULL;
3906         uint8_t additional_flags = 0;
3907
3908         req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
3909         if (req == NULL) {
3910                 return NULL;
3911         }
3912
3913         subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
3914                               0, NULL, 0, NULL);
3915         if (tevent_req_nomem(subreq, req)) {
3916                 return tevent_req_post(req, ev);
3917         }
3918         tevent_req_set_callback(subreq, cli_dskattr_done, req);
3919         return req;
3920 }
3921
3922 static void cli_dskattr_done(struct tevent_req *subreq)
3923 {
3924         struct tevent_req *req = tevent_req_callback_data(
3925                 subreq, struct tevent_req);
3926         struct cli_dskattr_state *state = tevent_req_data(
3927                 req, struct cli_dskattr_state);
3928         uint8_t wct;
3929         uint16_t *vwv = NULL;
3930         uint8_t *inbuf;
3931         NTSTATUS status;
3932
3933         status = cli_smb_recv(subreq, state, &inbuf, 4, &wct, &vwv, NULL,
3934                               NULL);
3935         TALLOC_FREE(subreq);
3936         if (!NT_STATUS_IS_OK(status)) {
3937                 tevent_req_nterror(req, status);
3938                 return;
3939         }
3940         state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
3941         state->total = SVAL(vwv+0, 0);
3942         state->avail = SVAL(vwv+3, 0);
3943         tevent_req_done(req);
3944 }
3945
3946 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
3947 {
3948         struct cli_dskattr_state *state = tevent_req_data(
3949                                 req, struct cli_dskattr_state);
3950         NTSTATUS status;
3951
3952         if (tevent_req_is_nterror(req, &status)) {
3953                 return status;
3954         }
3955         *bsize = state->bsize;
3956         *total = state->total;
3957         *avail = state->avail;
3958         return NT_STATUS_OK;
3959 }
3960
3961 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3962 {
3963         TALLOC_CTX *frame = talloc_stackframe();
3964         struct event_context *ev = NULL;
3965         struct tevent_req *req = NULL;
3966         NTSTATUS status = NT_STATUS_OK;
3967
3968         if (cli_has_async_calls(cli)) {
3969                 /*
3970                  * Can't use sync call while an async call is in flight
3971                  */
3972                 status = NT_STATUS_INVALID_PARAMETER;
3973                 goto fail;
3974         }
3975
3976         ev = event_context_init(frame);
3977         if (ev == NULL) {
3978                 status = NT_STATUS_NO_MEMORY;
3979                 goto fail;
3980         }
3981
3982         req = cli_dskattr_send(frame, ev, cli);
3983         if (req == NULL) {
3984                 status = NT_STATUS_NO_MEMORY;
3985                 goto fail;
3986         }
3987
3988         if (!tevent_req_poll(req, ev)) {
3989                 status = map_nt_error_from_unix(errno);
3990                 goto fail;
3991         }
3992
3993         status = cli_dskattr_recv(req, bsize, total, avail);
3994
3995  fail:
3996         TALLOC_FREE(frame);
3997         if (!NT_STATUS_IS_OK(status)) {
3998                 cli_set_error(cli, status);
3999         }
4000         return status;
4001 }
4002
4003 /****************************************************************************
4004  Create and open a temporary file.
4005 ****************************************************************************/
4006
4007 static void cli_ctemp_done(struct tevent_req *subreq);
4008
4009 struct ctemp_state {
4010         uint16_t vwv[3];
4011         char *ret_path;
4012         uint16_t fnum;
4013 };
4014
4015 struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
4016                                 struct event_context *ev,
4017                                 struct cli_state *cli,
4018                                 const char *path)
4019 {
4020         struct tevent_req *req = NULL, *subreq = NULL;
4021         struct ctemp_state *state = NULL;
4022         uint8_t additional_flags = 0;
4023         uint8_t *bytes = NULL;
4024
4025         req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
4026         if (req == NULL) {
4027                 return NULL;
4028         }
4029
4030         SSVAL(state->vwv,0,0);
4031         SIVALS(state->vwv+1,0,-1);
4032
4033         bytes = talloc_array(state, uint8_t, 1);
4034         if (tevent_req_nomem(bytes, req)) {
4035                 return tevent_req_post(req, ev);
4036         }
4037         bytes[0] = 4;
4038         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), path,
4039                                    strlen(path)+1, NULL);
4040         if (tevent_req_nomem(bytes, req)) {
4041                 return tevent_req_post(req, ev);
4042         }
4043
4044         subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
4045                               3, state->vwv, talloc_get_size(bytes), bytes);
4046         if (tevent_req_nomem(subreq, req)) {
4047                 return tevent_req_post(req, ev);
4048         }
4049         tevent_req_set_callback(subreq, cli_ctemp_done, req);
4050         return req;
4051 }
4052
4053 static void cli_ctemp_done(struct tevent_req *subreq)
4054 {
4055         struct tevent_req *req = tevent_req_callback_data(
4056                                 subreq, struct tevent_req);
4057         struct ctemp_state *state = tevent_req_data(
4058                                 req, struct ctemp_state);
4059         NTSTATUS status;
4060         uint8_t wcnt;
4061         uint16_t *vwv;
4062         uint32_t num_bytes = 0;
4063         uint8_t *bytes = NULL;
4064
4065         status = cli_smb_recv(subreq, NULL, NULL, 1, &wcnt, &vwv,
4066                               &num_bytes, &bytes);
4067         if (!NT_STATUS_IS_OK(status)) {
4068                 TALLOC_FREE(subreq);
4069                 tevent_req_nterror(req, status);
4070                 return;
4071         }
4072
4073         state->fnum = SVAL(vwv+0, 0);
4074
4075         TALLOC_FREE(subreq);
4076
4077         /* From W2K3, the result is just the ASCII name */
4078         if (num_bytes < 2) {
4079                 tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
4080                 return;
4081         }
4082
4083         if (pull_string_talloc(state,
4084                         NULL,
4085                         0,
4086                         &state->ret_path,
4087                         bytes,
4088                         num_bytes,
4089                         STR_ASCII) == 0) {
4090                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
4091                 return;
4092         }
4093         tevent_req_done(req);
4094 }
4095
4096 NTSTATUS cli_ctemp_recv(struct tevent_req *req,
4097                         TALLOC_CTX *ctx,
4098                         uint16_t *pfnum,
4099                         char **outfile)
4100 {
4101         struct ctemp_state *state = tevent_req_data(req,
4102                         struct ctemp_state);
4103         NTSTATUS status;
4104
4105         if (tevent_req_is_nterror(req, &status)) {
4106                 return status;
4107         }
4108         *pfnum = state->fnum;
4109         *outfile = talloc_strdup(ctx, state->ret_path);
4110         if (!*outfile) {
4111                 return NT_STATUS_NO_MEMORY;
4112         }
4113         return NT_STATUS_OK;
4114 }
4115
4116 NTSTATUS cli_ctemp(struct cli_state *cli,
4117                         TALLOC_CTX *ctx,
4118                         const char *path,
4119                         uint16_t *pfnum,
4120                         char **out_path)
4121 {
4122         TALLOC_CTX *frame = talloc_stackframe();
4123         struct event_context *ev;
4124         struct tevent_req *req;
4125         NTSTATUS status = NT_STATUS_OK;
4126
4127         if (cli_has_async_calls(cli)) {
4128                 /*
4129                  * Can't use sync call while an async call is in flight
4130                  */
4131                 status = NT_STATUS_INVALID_PARAMETER;
4132                 goto fail;
4133         }
4134
4135         ev = event_context_init(frame);
4136         if (ev == NULL) {
4137                 status = NT_STATUS_NO_MEMORY;
4138                 goto fail;
4139         }
4140
4141         req = cli_ctemp_send(frame, ev, cli, path);
4142         if (req == NULL) {
4143                 status = NT_STATUS_NO_MEMORY;
4144                 goto fail;
4145         }
4146
4147         if (!tevent_req_poll(req, ev)) {
4148                 status = map_nt_error_from_unix(errno);
4149                 goto fail;
4150         }
4151
4152         status = cli_ctemp_recv(req, ctx, pfnum, out_path);
4153
4154  fail:
4155         TALLOC_FREE(frame);
4156         if (!NT_STATUS_IS_OK(status)) {
4157                 cli_set_error(cli, status);
4158         }
4159         return status;
4160 }
4161
4162 /*
4163    send a raw ioctl - used by the torture code
4164 */
4165 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
4166 {
4167         uint16_t vwv[3];
4168         NTSTATUS status;
4169         struct tevent_req *result_parent;
4170
4171         SSVAL(vwv+0, 0, fnum);
4172         SSVAL(vwv+1, 0, code>>16);
4173         SSVAL(vwv+2, 0, (code&0xFFFF));
4174
4175         status = cli_smb(talloc_tos(), cli, SMBioctl, 0, 3, vwv, 0, NULL,
4176                          &result_parent, 0, NULL, NULL, NULL, NULL);
4177         if (!NT_STATUS_IS_OK(status)) {
4178                 return status;
4179         }
4180         *blob = data_blob_null;
4181         return NT_STATUS_OK;
4182 }
4183
4184 /*********************************************************
4185  Set an extended attribute utility fn.
4186 *********************************************************/
4187
4188 static bool cli_set_ea(struct cli_state *cli, uint16_t setup, char *param, unsigned int param_len,
4189                         const char *ea_name, const char *ea_val, size_t ea_len)
4190 {
4191         unsigned int data_len = 0;
4192         char *data = NULL;
4193         char *rparam=NULL, *rdata=NULL;
4194         char *p;
4195         size_t ea_namelen = strlen(ea_name);
4196
4197         if (ea_namelen == 0 && ea_len == 0) {
4198                 data_len = 4;
4199                 data = (char *)SMB_MALLOC(data_len);
4200                 if (!data) {
4201                         return False;
4202                 }
4203                 p = data;
4204                 SIVAL(p,0,data_len);
4205         } else {
4206                 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
4207                 data = (char *)SMB_MALLOC(data_len);
4208                 if (!data) {
4209                         return False;
4210                 }
4211                 p = data;
4212                 SIVAL(p,0,data_len);
4213                 p += 4;
4214                 SCVAL(p, 0, 0); /* EA flags. */
4215                 SCVAL(p, 1, ea_namelen);
4216                 SSVAL(p, 2, ea_len);
4217                 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
4218                 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
4219         }
4220
4221         if (!cli_send_trans(cli, SMBtrans2,
4222                         NULL,                        /* name */
4223                         -1, 0,                          /* fid, flags */
4224                         &setup, 1, 0,                   /* setup, length, max */
4225                         param, param_len, 2,            /* param, length, max */
4226                         data,  data_len, cli->max_xmit /* data, length, max */
4227                         )) {
4228                 SAFE_FREE(data);
4229                 return False;
4230         }
4231
4232         if (!cli_receive_trans(cli, SMBtrans2,
4233                         &rparam, &param_len,
4234                         &rdata, &data_len)) {
4235                         SAFE_FREE(data);
4236                 return false;
4237         }
4238
4239         SAFE_FREE(data);
4240         SAFE_FREE(rdata);
4241         SAFE_FREE(rparam);
4242
4243         return True;
4244 }
4245
4246 /*********************************************************
4247  Set an extended attribute on a pathname.
4248 *********************************************************/
4249
4250 bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len)
4251 {
4252         uint16_t setup = TRANSACT2_SETPATHINFO;
4253         unsigned int param_len = 0;
4254         char *param;
4255         size_t srclen = 2*(strlen(path)+1);
4256         char *p;
4257         bool ret;
4258
4259         param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
4260         if (!param) {
4261                 return false;
4262         }
4263         memset(param, '\0', 6);
4264         SSVAL(param,0,SMB_INFO_SET_EA);
4265         p = &param[6];
4266
4267         p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
4268         param_len = PTR_DIFF(p, param);
4269
4270         ret = cli_set_ea(cli, setup, param, param_len, ea_name, ea_val, ea_len);
4271         SAFE_FREE(param);
4272         return ret;
4273 }
4274
4275 /*********************************************************
4276  Set an extended attribute on an fnum.
4277 *********************************************************/
4278
4279 bool cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum, const char *ea_name, const char *ea_val, size_t ea_len)
4280 {
4281         char param[6];
4282         uint16_t setup = TRANSACT2_SETFILEINFO;
4283
4284         memset(param, 0, 6);
4285         SSVAL(param,0,fnum);
4286         SSVAL(param,2,SMB_INFO_SET_EA);
4287
4288         return cli_set_ea(cli, setup, param, 6, ea_name, ea_val, ea_len);
4289 }
4290
4291 /*********************************************************
4292  Get an extended attribute list utility fn.
4293 *********************************************************/
4294
4295 static bool cli_get_ea_list(struct cli_state *cli,
4296                 uint16_t setup, char *param, unsigned int param_len,
4297                 TALLOC_CTX *ctx,
4298                 size_t *pnum_eas,
4299                 struct ea_struct **pea_list)
4300 {
4301         unsigned int data_len = 0;
4302         unsigned int rparam_len, rdata_len;
4303         char *rparam=NULL, *rdata=NULL;
4304         char *p;
4305         size_t ea_size;
4306         size_t num_eas;
4307         bool ret = False;
4308         struct ea_struct *ea_list;
4309
4310         *pnum_eas = 0;
4311         if (pea_list) {
4312                 *pea_list = NULL;
4313         }
4314
4315         if (!cli_send_trans(cli, SMBtrans2,
4316                         NULL,           /* Name */
4317                         -1, 0,          /* fid, flags */
4318                         &setup, 1, 0,   /* setup, length, max */
4319                         param, param_len, 10, /* param, length, max */
4320                         NULL, data_len, cli->max_xmit /* data, length, max */
4321                                 )) {
4322                 return False;
4323         }
4324
4325         if (!cli_receive_trans(cli, SMBtrans2,
4326                         &rparam, &rparam_len,
4327                         &rdata, &rdata_len)) {
4328                 return False;
4329         }
4330
4331         if (!rdata || rdata_len < 4) {
4332                 goto out;
4333         }
4334
4335         ea_size = (size_t)IVAL(rdata,0);
4336         if (ea_size > rdata_len) {
4337                 goto out;
4338         }
4339
4340         if (ea_size == 0) {
4341                 /* No EA's present. */
4342                 ret = True;
4343                 goto out;
4344         }
4345
4346         p = rdata + 4;
4347         ea_size -= 4;
4348
4349         /* Validate the EA list and count it. */
4350         for (num_eas = 0; ea_size >= 4; num_eas++) {
4351                 unsigned int ea_namelen = CVAL(p,1);
4352                 unsigned int ea_valuelen = SVAL(p,2);
4353                 if (ea_namelen == 0) {
4354                         goto out;
4355                 }
4356                 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
4357                         goto out;
4358                 }
4359                 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
4360                 p += 4 + ea_namelen + 1 + ea_valuelen;
4361         }
4362
4363         if (num_eas == 0) {
4364                 ret = True;
4365                 goto out;
4366         }
4367
4368         *pnum_eas = num_eas;
4369         if (!pea_list) {
4370                 /* Caller only wants number of EA's. */
4371                 ret = True;
4372                 goto out;
4373         }
4374
4375         ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
4376         if (!ea_list) {
4377                 goto out;
4378         }
4379
4380         ea_size = (size_t)IVAL(rdata,0);
4381         p = rdata + 4;
4382
4383         for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
4384                 struct ea_struct *ea = &ea_list[num_eas];
4385                 fstring unix_ea_name;
4386                 unsigned int ea_namelen = CVAL(p,1);
4387                 unsigned int ea_valuelen = SVAL(p,2);
4388
4389                 ea->flags = CVAL(p,0);
4390                 unix_ea_name[0] = '\0';
4391                 pull_ascii_fstring(unix_ea_name, p + 4);
4392                 ea->name = talloc_strdup(ctx, unix_ea_name);
4393                 /* Ensure the value is null terminated (in case it's a string). */
4394                 ea->value = data_blob_talloc(ctx, NULL, ea_valuelen + 1);
4395                 if (!ea->value.data) {
4396                         goto out;
4397                 }
4398                 if (ea_valuelen) {
4399                         memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
4400                 }
4401                 ea->value.data[ea_valuelen] = 0;
4402                 ea->value.length--;
4403                 p += 4 + ea_namelen + 1 + ea_valuelen;
4404         }
4405
4406         *pea_list = ea_list;
4407         ret = True;
4408
4409  out :
4410
4411         SAFE_FREE(rdata);
4412         SAFE_FREE(rparam);
4413         return ret;
4414 }
4415
4416 /*********************************************************
4417  Get an extended attribute list from a pathname.
4418 *********************************************************/
4419
4420 bool cli_get_ea_list_path(struct cli_state *cli, const char *path,
4421                 TALLOC_CTX *ctx,
4422                 size_t *pnum_eas,
4423                 struct ea_struct **pea_list)
4424 {
4425         uint16_t setup = TRANSACT2_QPATHINFO;
4426         unsigned int param_len = 0;
4427         char *param;
4428         char *p;
4429         size_t srclen = 2*(strlen(path)+1);
4430         bool ret;
4431
4432         param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
4433         if (!param) {
4434                 return false;
4435         }
4436         p = param;
4437         memset(p, 0, 6);
4438         SSVAL(p, 0, SMB_INFO_QUERY_ALL_EAS);
4439         p += 6;
4440         p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
4441         param_len = PTR_DIFF(p, param);
4442
4443         ret = cli_get_ea_list(cli, setup, param, param_len, ctx, pnum_eas, pea_list);
4444         SAFE_FREE(param);
4445         return ret;
4446 }
4447
4448 /*********************************************************
4449  Get an extended attribute list from an fnum.
4450 *********************************************************/
4451
4452 bool cli_get_ea_list_fnum(struct cli_state *cli, uint16_t fnum,
4453                 TALLOC_CTX *ctx,
4454                 size_t *pnum_eas,
4455                 struct ea_struct **pea_list)
4456 {
4457         uint16_t setup = TRANSACT2_QFILEINFO;
4458         char param[6];
4459
4460         memset(param, 0, 6);
4461         SSVAL(param,0,fnum);
4462         SSVAL(param,2,SMB_INFO_SET_EA);
4463
4464         return cli_get_ea_list(cli, setup, param, 6, ctx, pnum_eas, pea_list);
4465 }
4466
4467 /****************************************************************************
4468  Convert open "flags" arg to uint32_t on wire.
4469 ****************************************************************************/
4470
4471 static uint32_t open_flags_to_wire(int flags)
4472 {
4473         int open_mode = flags & O_ACCMODE;
4474         uint32_t ret = 0;
4475
4476         switch (open_mode) {
4477                 case O_WRONLY:
4478                         ret |= SMB_O_WRONLY;
4479                         break;
4480                 case O_RDWR:
4481                         ret |= SMB_O_RDWR;
4482                         break;
4483                 default:
4484                 case O_RDONLY:
4485                         ret |= SMB_O_RDONLY;
4486                         break;
4487         }
4488
4489         if (flags & O_CREAT) {
4490                 ret |= SMB_O_CREAT;
4491         }
4492         if (flags & O_EXCL) {
4493                 ret |= SMB_O_EXCL;
4494         }
4495         if (flags & O_TRUNC) {
4496                 ret |= SMB_O_TRUNC;
4497         }
4498 #if defined(O_SYNC)
4499         if (flags & O_SYNC) {
4500                 ret |= SMB_O_SYNC;
4501         }
4502 #endif /* O_SYNC */
4503         if (flags & O_APPEND) {
4504                 ret |= SMB_O_APPEND;
4505         }
4506 #if defined(O_DIRECT)
4507         if (flags & O_DIRECT) {
4508                 ret |= SMB_O_DIRECT;
4509         }
4510 #endif
4511 #if defined(O_DIRECTORY)
4512         if (flags & O_DIRECTORY) {
4513                 ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4514                 ret |= SMB_O_DIRECTORY;
4515         }
4516 #endif
4517         return ret;
4518 }
4519
4520 /****************************************************************************
4521  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
4522 ****************************************************************************/
4523
4524 struct posix_open_state {
4525         uint16_t setup;
4526         uint8_t *param;
4527         uint8_t data[18];
4528         uint16_t fnum; /* Out */
4529 };
4530
4531 static void cli_posix_open_internal_done(struct tevent_req *subreq)
4532 {
4533         struct tevent_req *req = tevent_req_callback_data(
4534                                 subreq, struct tevent_req);
4535         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4536         NTSTATUS status;
4537         uint8_t *data;
4538         uint32_t num_data;
4539
4540         status = cli_trans_recv(subreq, state, NULL, 0, NULL, NULL, 0, NULL,
4541                                 &data, 12, &num_data);
4542         TALLOC_FREE(subreq);
4543         if (!NT_STATUS_IS_OK(status)) {
4544                 tevent_req_nterror(req, status);
4545                 return;
4546         }
4547         state->fnum = SVAL(data,2);
4548         tevent_req_done(req);
4549 }
4550
4551 static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
4552                                         struct event_context *ev,
4553                                         struct cli_state *cli,
4554                                         const char *fname,
4555                                         int flags,
4556                                         mode_t mode,
4557                                         bool is_dir)
4558 {
4559         struct tevent_req *req = NULL, *subreq = NULL;
4560         struct posix_open_state *state = NULL;
4561         uint32_t wire_flags = open_flags_to_wire(flags);
4562
4563         req = tevent_req_create(mem_ctx, &state, struct posix_open_state);
4564         if (req == NULL) {
4565                 return NULL;
4566         }
4567
4568         /* Setup setup word. */
4569         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4570
4571         /* Setup param array. */
4572         state->param = talloc_array(state, uint8_t, 6);
4573         if (tevent_req_nomem(state->param, req)) {
4574                 return tevent_req_post(req, ev);
4575         }
4576         memset(state->param, '\0', 6);
4577         SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
4578
4579         state->param = trans2_bytes_push_str(state->param, cli_ucs2(cli), fname,
4580                                    strlen(fname)+1, NULL);
4581
4582         if (tevent_req_nomem(state->param, req)) {
4583                 return tevent_req_post(req, ev);
4584         }
4585
4586         /* Setup data words. */
4587         if (is_dir) {
4588                 wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
4589                 wire_flags |= SMB_O_DIRECTORY;
4590         }
4591
4592         SIVAL(state->data,0,0); /* No oplock. */
4593         SIVAL(state->data,4,wire_flags);
4594         SIVAL(state->data,8,unix_perms_to_wire(mode));
4595         SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
4596         SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
4597
4598         subreq = cli_trans_send(state,                  /* mem ctx. */
4599                                 ev,                     /* event ctx. */
4600                                 cli,                    /* cli_state. */
4601                                 SMBtrans2,              /* cmd. */
4602                                 NULL,                   /* pipe name. */
4603                                 -1,                     /* fid. */
4604                                 0,                      /* function. */
4605                                 0,                      /* flags. */
4606                                 &state->setup,          /* setup. */
4607                                 1,                      /* num setup uint16_t words. */
4608                                 0,                      /* max returned setup. */
4609                                 state->param,           /* param. */
4610                                 talloc_get_size(state->param),/* num param. */
4611                                 2,                      /* max returned param. */
4612                                 state->data,            /* data. */
4613                                 18,                     /* num data. */
4614                                 12);                    /* max returned data. */
4615
4616         if (tevent_req_nomem(subreq, req)) {
4617                 return tevent_req_post(req, ev);
4618         }
4619         tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
4620         return req;
4621 }
4622
4623 struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
4624                                         struct event_context *ev,
4625                                         struct cli_state *cli,
4626                                         const char *fname,
4627                                         int flags,
4628                                         mode_t mode)
4629 {
4630         return cli_posix_open_internal_send(mem_ctx, ev,
4631                                 cli, fname, flags, mode, false);
4632 }
4633
4634 NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
4635 {
4636         struct posix_open_state *state = tevent_req_data(req, struct posix_open_state);
4637         NTSTATUS status;
4638
4639         if (tevent_req_is_nterror(req, &status)) {
4640                 return status;
4641         }
4642         *pfnum = state->fnum;
4643         return NT_STATUS_OK;
4644 }
4645
4646 /****************************************************************************
4647  Open - POSIX semantics. Doesn't request oplock.
4648 ****************************************************************************/
4649
4650 NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
4651                         int flags, mode_t mode, uint16_t *pfnum)
4652 {
4653
4654         TALLOC_CTX *frame = talloc_stackframe();
4655         struct event_context *ev = NULL;
4656         struct tevent_req *req = NULL;
4657         NTSTATUS status = NT_STATUS_OK;
4658
4659         if (cli_has_async_calls(cli)) {
4660                 /*
4661                  * Can't use sync call while an async call is in flight
4662                  */
4663                 status = NT_STATUS_INVALID_PARAMETER;
4664                 goto fail;
4665         }
4666
4667         ev = event_context_init(frame);
4668         if (ev == NULL) {
4669                 status = NT_STATUS_NO_MEMORY;
4670                 goto fail;
4671         }
4672
4673         req = cli_posix_open_send(frame,
4674                                 ev,
4675                                 cli,
4676                                 fname,
4677                                 flags,
4678                                 mode);
4679         if (req == NULL) {
4680                 status = NT_STATUS_NO_MEMORY;
4681                 goto fail;
4682         }
4683
4684         if (!tevent_req_poll(req, ev)) {
4685                 status = map_nt_error_from_unix(errno);
4686                 goto fail;
4687         }
4688
4689         status = cli_posix_open_recv(req, pfnum);
4690
4691  fail:
4692         TALLOC_FREE(frame);
4693         if (!NT_STATUS_IS_OK(status)) {
4694                 cli_set_error(cli, status);
4695         }
4696         return status;
4697 }
4698
4699 struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
4700                                         struct event_context *ev,
4701                                         struct cli_state *cli,
4702                                         const char *fname,
4703                                         mode_t mode)
4704 {
4705         return cli_posix_open_internal_send(mem_ctx, ev,
4706                                 cli, fname, O_CREAT, mode, true);
4707 }
4708
4709 NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
4710 {
4711         NTSTATUS status;
4712
4713         if (tevent_req_is_nterror(req, &status)) {
4714                 return status;
4715         }
4716         return NT_STATUS_OK;
4717 }
4718
4719 NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
4720 {
4721         TALLOC_CTX *frame = talloc_stackframe();
4722         struct event_context *ev = NULL;
4723         struct tevent_req *req = NULL;
4724         NTSTATUS status = NT_STATUS_OK;
4725
4726         if (cli_has_async_calls(cli)) {
4727                 /*
4728                  * Can't use sync call while an async call is in flight
4729                  */
4730                 status = NT_STATUS_INVALID_PARAMETER;
4731                 goto fail;
4732         }
4733
4734         ev = event_context_init(frame);
4735         if (ev == NULL) {
4736                 status = NT_STATUS_NO_MEMORY;
4737                 goto fail;
4738         }
4739
4740         req = cli_posix_mkdir_send(frame,
4741                                 ev,
4742                                 cli,
4743                                 fname,
4744                                 mode);
4745         if (req == NULL) {
4746                 status = NT_STATUS_NO_MEMORY;
4747                 goto fail;
4748         }
4749
4750         if (!tevent_req_poll(req, ev)) {
4751                 status = map_nt_error_from_unix(errno);
4752                 goto fail;
4753         }
4754
4755         status = cli_posix_mkdir_recv(req);
4756
4757  fail:
4758         TALLOC_FREE(frame);
4759         if (!NT_STATUS_IS_OK(status)) {
4760                 cli_set_error(cli, status);
4761         }
4762         return status;
4763 }
4764
4765 /****************************************************************************
4766  unlink or rmdir - POSIX semantics.
4767 ****************************************************************************/
4768
4769 struct unlink_state {
4770         uint16_t setup;
4771         uint8_t data[2];
4772 };
4773
4774 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
4775 {
4776         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
4777                                          NULL, 0, NULL, NULL, 0, NULL);
4778         tevent_req_simple_finish_ntstatus(subreq, status);
4779 }
4780
4781 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
4782                                         struct event_context *ev,
4783                                         struct cli_state *cli,
4784                                         const char *fname,
4785                                         bool is_dir)
4786 {
4787         struct tevent_req *req = NULL, *subreq = NULL;
4788         struct unlink_state *state = NULL;
4789         uint8_t *param = NULL;
4790
4791         req = tevent_req_create(mem_ctx, &state, struct unlink_state);
4792         if (req == NULL) {
4793                 return NULL;
4794         }
4795
4796         /* Setup setup word. */
4797         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
4798
4799         /* Setup param array. */
4800         param = talloc_array(state, uint8_t, 6);
4801         if (tevent_req_nomem(param, req)) {
4802                 return tevent_req_post(req, ev);
4803         }
4804         memset(param, '\0', 6);
4805         SSVAL(param, 0, SMB_POSIX_PATH_UNLINK);
4806
4807         param = trans2_bytes_push_str(param, cli_ucs2(cli), fname,
4808                                    strlen(fname)+1, NULL);
4809
4810         if (tevent_req_nomem(param, req)) {
4811                 return tevent_req_post(req, ev);
4812         }
4813
4814         /* Setup data word. */
4815         SSVAL(state->data, 0, is_dir ? SMB_POSIX_UNLINK_DIRECTORY_TARGET :
4816                         SMB_POSIX_UNLINK_FILE_TARGET);
4817
4818         subreq = cli_trans_send(state,                  /* mem ctx. */
4819                                 ev,                     /* event ctx. */
4820                                 cli,                    /* cli_state. */
4821                                 SMBtrans2,              /* cmd. */
4822                                 NULL,                   /* pipe name. */
4823                                 -1,                     /* fid. */
4824                                 0,                      /* function. */
4825                                 0,                      /* flags. */
4826                                 &state->setup,          /* setup. */
4827                                 1,                      /* num setup uint16_t words. */
4828                                 0,                      /* max returned setup. */
4829                                 param,                  /* param. */
4830                                 talloc_get_size(param), /* num param. */
4831                                 2,                      /* max returned param. */
4832                                 state->data,            /* data. */
4833                                 2,                      /* num data. */
4834                                 0);                     /* max returned data. */
4835
4836         if (tevent_req_nomem(subreq, req)) {
4837                 return tevent_req_post(req, ev);
4838         }
4839         tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
4840         return req;
4841 }
4842
4843 struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
4844                                         struct event_context *ev,
4845                                         struct cli_state *cli,
4846                                         const char *fname)
4847 {
4848         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, false);
4849 }
4850
4851 NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
4852 {
4853         NTSTATUS status;
4854
4855         if (tevent_req_is_nterror(req, &status)) {
4856                 return status;
4857         }
4858         return NT_STATUS_OK;
4859 }
4860
4861 /****************************************************************************
4862  unlink - POSIX semantics.
4863 ****************************************************************************/
4864
4865 NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
4866 {
4867         TALLOC_CTX *frame = talloc_stackframe();
4868         struct event_context *ev = NULL;
4869         struct tevent_req *req = NULL;
4870         NTSTATUS status = NT_STATUS_OK;
4871
4872         if (cli_has_async_calls(cli)) {
4873                 /*
4874                  * Can't use sync call while an async call is in flight
4875                  */
4876                 status = NT_STATUS_INVALID_PARAMETER;
4877                 goto fail;
4878         }
4879
4880         ev = event_context_init(frame);
4881         if (ev == NULL) {
4882                 status = NT_STATUS_NO_MEMORY;
4883                 goto fail;
4884         }
4885
4886         req = cli_posix_unlink_send(frame,
4887                                 ev,
4888                                 cli,
4889                                 fname);
4890         if (req == NULL) {
4891                 status = NT_STATUS_NO_MEMORY;
4892                 goto fail;
4893         }
4894
4895         if (!tevent_req_poll(req, ev)) {
4896                 status = map_nt_error_from_unix(errno);
4897                 goto fail;
4898         }
4899
4900         status = cli_posix_unlink_recv(req);
4901
4902  fail:
4903         TALLOC_FREE(frame);
4904         if (!NT_STATUS_IS_OK(status)) {
4905                 cli_set_error(cli, status);
4906         }
4907         return status;
4908 }
4909
4910 /****************************************************************************
4911  rmdir - POSIX semantics.
4912 ****************************************************************************/
4913
4914 struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
4915                                         struct event_context *ev,
4916                                         struct cli_state *cli,
4917                                         const char *fname)
4918 {
4919         return cli_posix_unlink_internal_send(mem_ctx, ev, cli, fname, true);
4920 }
4921
4922 NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
4923 {
4924         NTSTATUS status;
4925
4926         if (tevent_req_is_nterror(req, &status)) {
4927                 return status;
4928         }
4929         return NT_STATUS_OK;
4930 }
4931
4932 NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
4933 {
4934         TALLOC_CTX *frame = talloc_stackframe();
4935         struct event_context *ev = NULL;
4936         struct tevent_req *req = NULL;
4937         NTSTATUS status = NT_STATUS_OK;
4938
4939         if (cli_has_async_calls(cli)) {
4940                 /*
4941                  * Can't use sync call while an async call is in flight
4942                  */
4943                 status = NT_STATUS_INVALID_PARAMETER;
4944                 goto fail;
4945         }
4946
4947         ev = event_context_init(frame);
4948         if (ev == NULL) {
4949                 status = NT_STATUS_NO_MEMORY;
4950                 goto fail;
4951         }
4952
4953         req = cli_posix_rmdir_send(frame,
4954                                 ev,
4955                                 cli,
4956                                 fname);
4957         if (req == NULL) {
4958                 status = NT_STATUS_NO_MEMORY;
4959                 goto fail;
4960         }
4961
4962         if (!tevent_req_poll(req, ev)) {
4963                 status = map_nt_error_from_unix(errno);
4964                 goto fail;
4965         }
4966
4967         status = cli_posix_rmdir_recv(req, frame);
4968
4969  fail:
4970         TALLOC_FREE(frame);
4971         if (!NT_STATUS_IS_OK(status)) {
4972                 cli_set_error(cli, status);
4973         }
4974         return status;
4975 }
4976
4977 /****************************************************************************
4978  filechangenotify
4979 ****************************************************************************/
4980
4981 struct cli_notify_state {
4982         uint8_t setup[8];
4983         uint32_t num_changes;
4984         struct notify_change *changes;
4985 };
4986
4987 static void cli_notify_done(struct tevent_req *subreq);
4988
4989 struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
4990                                    struct tevent_context *ev,
4991                                    struct cli_state *cli, uint16_t fnum,
4992                                    uint32_t buffer_size,
4993                                    uint32_t completion_filter, bool recursive)
4994 {
4995         struct tevent_req *req, *subreq;
4996         struct cli_notify_state *state;
4997
4998         req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
4999         if (req == NULL) {
5000                 return NULL;
5001         }
5002
5003         SIVAL(state->setup, 0, completion_filter);
5004         SSVAL(state->setup, 4, fnum);
5005         SSVAL(state->setup, 6, recursive);
5006
5007         subreq = cli_trans_send(
5008                 state,                  /* mem ctx. */
5009                 ev,                     /* event ctx. */
5010                 cli,                    /* cli_state. */
5011                 SMBnttrans,             /* cmd. */
5012                 NULL,                   /* pipe name. */
5013                 -1,                     /* fid. */
5014                 NT_TRANSACT_NOTIFY_CHANGE, /* function. */
5015                 0,                      /* flags. */
5016                 (uint16_t *)state->setup, /* setup. */
5017                 4,                      /* num setup uint16_t words. */
5018                 0,                      /* max returned setup. */
5019                 NULL,                   /* param. */
5020                 0,                      /* num param. */
5021                 buffer_size,            /* max returned param. */
5022                 NULL,                   /* data. */
5023                 0,                      /* num data. */
5024                 0);                     /* max returned data. */
5025
5026         if (tevent_req_nomem(subreq, req)) {
5027                 return tevent_req_post(req, ev);
5028         }
5029         tevent_req_set_callback(subreq, cli_notify_done, req);
5030         return req;
5031 }
5032
5033 static void cli_notify_done(struct tevent_req *subreq)
5034 {
5035         struct tevent_req *req = tevent_req_callback_data(
5036                 subreq, struct tevent_req);
5037         struct cli_notify_state *state = tevent_req_data(
5038                 req, struct cli_notify_state);
5039         NTSTATUS status;
5040         uint8_t *params;
5041         uint32_t i, ofs, num_params;
5042
5043         status = cli_trans_recv(subreq, talloc_tos(), NULL, 0, NULL,
5044                                 &params, 0, &num_params, NULL, 0, NULL);
5045         TALLOC_FREE(subreq);
5046         if (!NT_STATUS_IS_OK(status)) {
5047                 DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
5048                 tevent_req_nterror(req, status);
5049                 return;
5050         }
5051
5052         state->num_changes = 0;
5053         ofs = 0;
5054
5055         while (num_params - ofs > 12) {
5056                 uint32_t len = IVAL(params, ofs);
5057                 state->num_changes += 1;
5058
5059                 if ((len == 0) || (ofs+len >= num_params)) {
5060                         break;
5061                 }
5062                 ofs += len;
5063         }
5064
5065         state->changes = talloc_array(state, struct notify_change,
5066                                       state->num_changes);
5067         if (tevent_req_nomem(state->changes, req)) {
5068                 TALLOC_FREE(params);
5069                 return;
5070         }
5071
5072         ofs = 0;
5073
5074         for (i=0; i<state->num_changes; i++) {
5075                 uint32_t next = IVAL(params, ofs);
5076                 uint32_t len = IVAL(params, ofs+8);
5077                 ssize_t ret;
5078                 char *name;
5079
5080                 if ((next != 0) && (len+12 != next)) {
5081                         TALLOC_FREE(params);
5082                         tevent_req_nterror(
5083                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
5084                         return;
5085                 }
5086
5087                 state->changes[i].action = IVAL(params, ofs+4);
5088                 ret = clistr_pull_talloc(params, (char *)params, &name,
5089                                          params+ofs+12, len,
5090                                          STR_TERMINATE|STR_UNICODE);
5091                 if (ret == -1) {
5092                         TALLOC_FREE(params);
5093                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
5094                         return;
5095                 }
5096                 state->changes[i].name = name;
5097                 ofs += next;
5098         }
5099
5100         TALLOC_FREE(params);
5101         tevent_req_done(req);
5102 }
5103
5104 NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5105                          uint32_t *pnum_changes,
5106                          struct notify_change **pchanges)
5107 {
5108         struct cli_notify_state *state = tevent_req_data(
5109                 req, struct cli_notify_state);
5110         NTSTATUS status;
5111
5112         if (tevent_req_is_nterror(req, &status)) {
5113                 return status;
5114         }
5115
5116         *pnum_changes = state->num_changes;
5117         *pchanges = talloc_move(mem_ctx, &state->changes);
5118         return NT_STATUS_OK;
5119 }