fb4857a1a516af8cd219b383a8a11e7f2ec7f737
[sfrench/samba-autobuild/.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, 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, 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, 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, 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, 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         NTSTATUS status;
2042
2043         status = cli_smb_recv(subreq, 3, &wct, &vwv, &num_bytes, &bytes);
2044         if (!NT_STATUS_IS_OK(status)) {
2045                 TALLOC_FREE(subreq);
2046                 tevent_req_nterror(req, status);
2047                 return;
2048         }
2049         state->fnum = SVAL(vwv+2, 1);
2050         tevent_req_done(req);
2051 }
2052
2053 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
2054 {
2055         struct cli_ntcreate_state *state = tevent_req_data(
2056                 req, struct cli_ntcreate_state);
2057         NTSTATUS status;
2058
2059         if (tevent_req_is_nterror(req, &status)) {
2060                 return status;
2061         }
2062         *pfnum = state->fnum;
2063         return NT_STATUS_OK;
2064 }
2065
2066 NTSTATUS cli_ntcreate(struct cli_state *cli,
2067                       const char *fname,
2068                       uint32_t CreatFlags,
2069                       uint32_t DesiredAccess,
2070                       uint32_t FileAttributes,
2071                       uint32_t ShareAccess,
2072                       uint32_t CreateDisposition,
2073                       uint32_t CreateOptions,
2074                       uint8_t SecurityFlags,
2075                       uint16_t *pfid)
2076 {
2077         TALLOC_CTX *frame = talloc_stackframe();
2078         struct event_context *ev;
2079         struct tevent_req *req;
2080         NTSTATUS status = NT_STATUS_OK;
2081
2082         if (cli_has_async_calls(cli)) {
2083                 /*
2084                  * Can't use sync call while an async call is in flight
2085                  */
2086                 status = NT_STATUS_INVALID_PARAMETER;
2087                 goto fail;
2088         }
2089
2090         ev = event_context_init(frame);
2091         if (ev == NULL) {
2092                 status = NT_STATUS_NO_MEMORY;
2093                 goto fail;
2094         }
2095
2096         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
2097                                 DesiredAccess, FileAttributes, ShareAccess,
2098                                 CreateDisposition, CreateOptions,
2099                                 SecurityFlags);
2100         if (req == NULL) {
2101                 status = NT_STATUS_NO_MEMORY;
2102                 goto fail;
2103         }
2104
2105         if (!tevent_req_poll(req, ev)) {
2106                 status = map_nt_error_from_unix(errno);
2107                 goto fail;
2108         }
2109
2110         status = cli_ntcreate_recv(req, pfid);
2111  fail:
2112         TALLOC_FREE(frame);
2113         if (!NT_STATUS_IS_OK(status)) {
2114                 cli_set_error(cli, status);
2115         }
2116         return status;
2117 }
2118
2119 /****************************************************************************
2120  Open a file
2121  WARNING: if you open with O_WRONLY then getattrE won't work!
2122 ****************************************************************************/
2123
2124 struct cli_open_state {
2125         uint16_t vwv[15];
2126         uint16_t fnum;
2127         struct iovec bytes;
2128 };
2129
2130 static void cli_open_done(struct tevent_req *subreq);
2131
2132 struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx,
2133                                    struct event_context *ev,
2134                                    struct cli_state *cli, const char *fname,
2135                                    int flags, int share_mode,
2136                                    struct tevent_req **psmbreq)
2137 {
2138         struct tevent_req *req, *subreq;
2139         struct cli_open_state *state;
2140         unsigned openfn;
2141         unsigned accessmode;
2142         uint8_t additional_flags;
2143         uint8_t *bytes;
2144
2145         req = tevent_req_create(mem_ctx, &state, struct cli_open_state);
2146         if (req == NULL) {
2147                 return NULL;
2148         }
2149
2150         openfn = 0;
2151         if (flags & O_CREAT) {
2152                 openfn |= (1<<4);
2153         }
2154         if (!(flags & O_EXCL)) {
2155                 if (flags & O_TRUNC)
2156                         openfn |= (1<<1);
2157                 else
2158                         openfn |= (1<<0);
2159         }
2160
2161         accessmode = (share_mode<<4);
2162
2163         if ((flags & O_ACCMODE) == O_RDWR) {
2164                 accessmode |= 2;
2165         } else if ((flags & O_ACCMODE) == O_WRONLY) {
2166                 accessmode |= 1;
2167         }
2168
2169 #if defined(O_SYNC)
2170         if ((flags & O_SYNC) == O_SYNC) {
2171                 accessmode |= (1<<14);
2172         }
2173 #endif /* O_SYNC */
2174
2175         if (share_mode == DENY_FCB) {
2176                 accessmode = 0xFF;
2177         }
2178
2179         SCVAL(state->vwv + 0, 0, 0xFF);
2180         SCVAL(state->vwv + 0, 1, 0);
2181         SSVAL(state->vwv + 1, 0, 0);
2182         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
2183         SSVAL(state->vwv + 3, 0, accessmode);
2184         SSVAL(state->vwv + 4, 0, aSYSTEM | aHIDDEN);
2185         SSVAL(state->vwv + 5, 0, 0);
2186         SIVAL(state->vwv + 6, 0, 0);
2187         SSVAL(state->vwv + 8, 0, openfn);
2188         SIVAL(state->vwv + 9, 0, 0);
2189         SIVAL(state->vwv + 11, 0, 0);
2190         SIVAL(state->vwv + 13, 0, 0);
2191
2192         additional_flags = 0;
2193
2194         if (cli->use_oplocks) {
2195                 /* if using oplocks then ask for a batch oplock via
2196                    core and extended methods */
2197                 additional_flags =
2198                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
2199                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
2200         }
2201
2202         bytes = talloc_array(state, uint8_t, 0);
2203         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
2204                                    strlen(fname)+1, NULL);
2205
2206         if (tevent_req_nomem(bytes, req)) {
2207                 return tevent_req_post(req, ev);
2208         }
2209
2210         state->bytes.iov_base = (void *)bytes;
2211         state->bytes.iov_len = talloc_get_size(bytes);
2212
2213         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
2214                                     15, state->vwv, 1, &state->bytes);
2215         if (subreq == NULL) {
2216                 TALLOC_FREE(req);
2217                 return NULL;
2218         }
2219         tevent_req_set_callback(subreq, cli_open_done, req);
2220         *psmbreq = subreq;
2221         return req;
2222 }
2223
2224 struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
2225                                  struct cli_state *cli, const char *fname,
2226                                  int flags, int share_mode)
2227 {
2228         struct tevent_req *req, *subreq;
2229         NTSTATUS status;
2230
2231         req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode,
2232                               &subreq);
2233         if (req == NULL) {
2234                 return NULL;
2235         }
2236
2237         status = cli_smb_req_send(subreq);
2238         if (!NT_STATUS_IS_OK(status)) {
2239                 tevent_req_nterror(req, status);
2240                 return tevent_req_post(req, ev);
2241         }
2242         return req;
2243 }
2244
2245 static void cli_open_done(struct tevent_req *subreq)
2246 {
2247         struct tevent_req *req = tevent_req_callback_data(
2248                 subreq, struct tevent_req);
2249         struct cli_open_state *state = tevent_req_data(
2250                 req, struct cli_open_state);
2251         uint8_t wct;
2252         uint16_t *vwv;
2253         NTSTATUS status;
2254
2255         status = cli_smb_recv(subreq, 3, &wct, &vwv, NULL, NULL);
2256         if (!NT_STATUS_IS_OK(status)) {
2257                 TALLOC_FREE(subreq);
2258                 tevent_req_nterror(req, status);
2259                 return;
2260         }
2261         state->fnum = SVAL(vwv+2, 0);
2262         tevent_req_done(req);
2263 }
2264
2265 NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum)
2266 {
2267         struct cli_open_state *state = tevent_req_data(
2268                 req, struct cli_open_state);
2269         NTSTATUS status;
2270
2271         if (tevent_req_is_nterror(req, &status)) {
2272                 return status;
2273         }
2274         *pfnum = state->fnum;
2275         return NT_STATUS_OK;
2276 }
2277
2278 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
2279              int share_mode, uint16_t *pfnum)
2280 {
2281         TALLOC_CTX *frame = talloc_stackframe();
2282         struct event_context *ev;
2283         struct tevent_req *req;
2284         NTSTATUS status = NT_STATUS_OK;
2285
2286         if (cli_has_async_calls(cli)) {
2287                 /*
2288                  * Can't use sync call while an async call is in flight
2289                  */
2290                 status = NT_STATUS_INVALID_PARAMETER;
2291                 goto fail;
2292         }
2293
2294         ev = event_context_init(frame);
2295         if (ev == NULL) {
2296                 status = NT_STATUS_NO_MEMORY;
2297                 goto fail;
2298         }
2299
2300         req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
2301         if (req == NULL) {
2302                 status = NT_STATUS_NO_MEMORY;
2303                 goto fail;
2304         }
2305
2306         if (!tevent_req_poll(req, ev)) {
2307                 status = map_nt_error_from_unix(errno);
2308                 goto fail;
2309         }
2310
2311         status = cli_open_recv(req, pfnum);
2312  fail:
2313         TALLOC_FREE(frame);
2314         if (!NT_STATUS_IS_OK(status)) {
2315                 cli_set_error(cli, status);
2316         }
2317         return status;
2318 }
2319
2320 /****************************************************************************
2321  Close a file.
2322 ****************************************************************************/
2323
2324 struct cli_close_state {
2325         uint16_t vwv[3];
2326 };
2327
2328 static void cli_close_done(struct tevent_req *subreq);
2329
2330 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
2331                                 struct event_context *ev,
2332                                 struct cli_state *cli,
2333                                 uint16_t fnum,
2334                                 struct tevent_req **psubreq)
2335 {
2336         struct tevent_req *req, *subreq;
2337         struct cli_close_state *state;
2338
2339         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
2340         if (req == NULL) {
2341                 return NULL;
2342         }
2343
2344         SSVAL(state->vwv+0, 0, fnum);
2345         SIVALS(state->vwv+1, 0, -1);
2346
2347         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
2348                                     0, NULL);
2349         if (subreq == NULL) {
2350                 TALLOC_FREE(req);
2351                 return NULL;
2352         }
2353         tevent_req_set_callback(subreq, cli_close_done, req);
2354         *psubreq = subreq;
2355         return req;
2356 }
2357
2358 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
2359                                 struct event_context *ev,
2360                                 struct cli_state *cli,
2361                                 uint16_t fnum)
2362 {
2363         struct tevent_req *req, *subreq;
2364         NTSTATUS status;
2365
2366         req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
2367         if (req == NULL) {
2368                 return NULL;
2369         }
2370
2371         status = cli_smb_req_send(subreq);
2372         if (!NT_STATUS_IS_OK(status)) {
2373                 tevent_req_nterror(req, status);
2374                 return tevent_req_post(req, ev);
2375         }
2376         return req;
2377 }
2378
2379 static void cli_close_done(struct tevent_req *subreq)
2380 {
2381         struct tevent_req *req = tevent_req_callback_data(
2382                 subreq, struct tevent_req);
2383         NTSTATUS status;
2384
2385         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2386         TALLOC_FREE(subreq);
2387         if (!NT_STATUS_IS_OK(status)) {
2388                 tevent_req_nterror(req, status);
2389                 return;
2390         }
2391         tevent_req_done(req);
2392 }
2393
2394 NTSTATUS cli_close_recv(struct tevent_req *req)
2395 {
2396         return tevent_req_simple_recv_ntstatus(req);
2397 }
2398
2399 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
2400 {
2401         TALLOC_CTX *frame = talloc_stackframe();
2402         struct event_context *ev;
2403         struct tevent_req *req;
2404         NTSTATUS status = NT_STATUS_OK;
2405
2406         if (cli_has_async_calls(cli)) {
2407                 /*
2408                  * Can't use sync call while an async call is in flight
2409                  */
2410                 status = NT_STATUS_INVALID_PARAMETER;
2411                 goto fail;
2412         }
2413
2414         ev = event_context_init(frame);
2415         if (ev == NULL) {
2416                 status = NT_STATUS_NO_MEMORY;
2417                 goto fail;
2418         }
2419
2420         req = cli_close_send(frame, ev, cli, fnum);
2421         if (req == NULL) {
2422                 status = NT_STATUS_NO_MEMORY;
2423                 goto fail;
2424         }
2425
2426         if (!tevent_req_poll(req, ev)) {
2427                 status = map_nt_error_from_unix(errno);
2428                 goto fail;
2429         }
2430
2431         status = cli_close_recv(req);
2432  fail:
2433         TALLOC_FREE(frame);
2434         if (!NT_STATUS_IS_OK(status)) {
2435                 cli_set_error(cli, status);
2436         }
2437         return status;
2438 }
2439
2440 /****************************************************************************
2441  Truncate a file to a specified size
2442 ****************************************************************************/
2443
2444 struct ftrunc_state {
2445         uint16_t setup;
2446         uint8_t param[6];
2447         uint8_t data[8];
2448 };
2449
2450 static void cli_ftruncate_done(struct tevent_req *subreq)
2451 {
2452         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
2453                                          NULL, 0, NULL, NULL, 0, NULL);
2454         tevent_req_simple_finish_ntstatus(subreq, status);
2455 }
2456
2457 struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
2458                                         struct event_context *ev,
2459                                         struct cli_state *cli,
2460                                         uint16_t fnum,
2461                                         uint64_t size)
2462 {
2463         struct tevent_req *req = NULL, *subreq = NULL;
2464         struct ftrunc_state *state = NULL;
2465
2466         req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
2467         if (req == NULL) {
2468                 return NULL;
2469         }
2470
2471         /* Setup setup word. */
2472         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
2473
2474         /* Setup param array. */
2475         SSVAL(state->param,0,fnum);
2476         SSVAL(state->param,2,SMB_SET_FILE_END_OF_FILE_INFO);
2477         SSVAL(state->param,4,0);
2478
2479         /* Setup data array. */
2480         SBVAL(state->data, 0, size);
2481
2482         subreq = cli_trans_send(state,                  /* mem ctx. */
2483                                 ev,                     /* event ctx. */
2484                                 cli,                    /* cli_state. */
2485                                 SMBtrans2,              /* cmd. */
2486                                 NULL,                   /* pipe name. */
2487                                 -1,                     /* fid. */
2488                                 0,                      /* function. */
2489                                 0,                      /* flags. */
2490                                 &state->setup,          /* setup. */
2491                                 1,                      /* num setup uint16_t words. */
2492                                 0,                      /* max returned setup. */
2493                                 state->param,           /* param. */
2494                                 6,                      /* num param. */
2495                                 2,                      /* max returned param. */
2496                                 state->data,            /* data. */
2497                                 8,                      /* num data. */
2498                                 0);                     /* max returned data. */
2499
2500         if (tevent_req_nomem(subreq, req)) {
2501                 return tevent_req_post(req, ev);
2502         }
2503         tevent_req_set_callback(subreq, cli_ftruncate_done, req);
2504         return req;
2505 }
2506
2507 NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
2508 {
2509         NTSTATUS status;
2510
2511         if (tevent_req_is_nterror(req, &status)) {
2512                 return status;
2513         }
2514         return NT_STATUS_OK;
2515 }
2516
2517 NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
2518 {
2519         TALLOC_CTX *frame = talloc_stackframe();
2520         struct event_context *ev = NULL;
2521         struct tevent_req *req = NULL;
2522         NTSTATUS status = NT_STATUS_OK;
2523
2524         if (cli_has_async_calls(cli)) {
2525                 /*
2526                  * Can't use sync call while an async call is in flight
2527                  */
2528                 status = NT_STATUS_INVALID_PARAMETER;
2529                 goto fail;
2530         }
2531
2532         ev = event_context_init(frame);
2533         if (ev == NULL) {
2534                 status = NT_STATUS_NO_MEMORY;
2535                 goto fail;
2536         }
2537
2538         req = cli_ftruncate_send(frame,
2539                                 ev,
2540                                 cli,
2541                                 fnum,
2542                                 size);
2543         if (req == NULL) {
2544                 status = NT_STATUS_NO_MEMORY;
2545                 goto fail;
2546         }
2547
2548         if (!tevent_req_poll(req, ev)) {
2549                 status = map_nt_error_from_unix(errno);
2550                 goto fail;
2551         }
2552
2553         status = cli_ftruncate_recv(req);
2554
2555  fail:
2556         TALLOC_FREE(frame);
2557         if (!NT_STATUS_IS_OK(status)) {
2558                 cli_set_error(cli, status);
2559         }
2560         return status;
2561 }
2562
2563 /****************************************************************************
2564  send a lock with a specified locktype
2565  this is used for testing LOCKING_ANDX_CANCEL_LOCK
2566 ****************************************************************************/
2567
2568 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
2569                       uint32_t offset, uint32_t len,
2570                       int timeout, unsigned char locktype)
2571 {
2572         char *p;
2573         int saved_timeout = cli->timeout;
2574
2575         memset(cli->outbuf,'\0',smb_size);
2576         memset(cli->inbuf,'\0', smb_size);
2577
2578         cli_set_message(cli->outbuf,8,0,True);
2579
2580         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2581         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2582         cli_setup_packet(cli);
2583
2584         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2585         SSVAL(cli->outbuf,smb_vwv2,fnum);
2586         SCVAL(cli->outbuf,smb_vwv3,locktype);
2587         SIVALS(cli->outbuf, smb_vwv4, timeout);
2588         SSVAL(cli->outbuf,smb_vwv6,0);
2589         SSVAL(cli->outbuf,smb_vwv7,1);
2590
2591         p = smb_buf(cli->outbuf);
2592         SSVAL(p, 0, cli->pid);
2593         SIVAL(p, 2, offset);
2594         SIVAL(p, 6, len);
2595
2596         p += 10;
2597
2598         cli_setup_bcc(cli, p);
2599
2600         cli_send_smb(cli);
2601
2602         if (timeout != 0) {
2603                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
2604         }
2605
2606         if (!cli_receive_smb(cli)) {
2607                 cli->timeout = saved_timeout;
2608                 return NT_STATUS_UNSUCCESSFUL;
2609         }
2610
2611         cli->timeout = saved_timeout;
2612
2613         return cli_nt_error(cli);
2614 }
2615
2616 /****************************************************************************
2617  Lock a file.
2618  note that timeout is in units of 2 milliseconds
2619 ****************************************************************************/
2620
2621 bool cli_lock(struct cli_state *cli, uint16_t fnum,
2622               uint32_t offset, uint32_t len, int timeout, enum brl_type lock_type)
2623 {
2624         char *p;
2625         int saved_timeout = cli->timeout;
2626
2627         memset(cli->outbuf,'\0',smb_size);
2628         memset(cli->inbuf,'\0', smb_size);
2629
2630         cli_set_message(cli->outbuf,8,0,True);
2631
2632         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2633         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2634         cli_setup_packet(cli);
2635
2636         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2637         SSVAL(cli->outbuf,smb_vwv2,fnum);
2638         SCVAL(cli->outbuf,smb_vwv3,(lock_type == READ_LOCK? 1 : 0));
2639         SIVALS(cli->outbuf, smb_vwv4, timeout);
2640         SSVAL(cli->outbuf,smb_vwv6,0);
2641         SSVAL(cli->outbuf,smb_vwv7,1);
2642
2643         p = smb_buf(cli->outbuf);
2644         SSVAL(p, 0, cli->pid);
2645         SIVAL(p, 2, offset);
2646         SIVAL(p, 6, len);
2647
2648         p += 10;
2649
2650         cli_setup_bcc(cli, p);
2651
2652         cli_send_smb(cli);
2653
2654         if (timeout != 0) {
2655                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout*2 + 5*1000);
2656         }
2657
2658         if (!cli_receive_smb(cli)) {
2659                 cli->timeout = saved_timeout;
2660                 return False;
2661         }
2662
2663         cli->timeout = saved_timeout;
2664
2665         if (cli_is_error(cli)) {
2666                 return False;
2667         }
2668
2669         return True;
2670 }
2671
2672 /****************************************************************************
2673  Unlock a file.
2674 ****************************************************************************/
2675
2676 struct cli_unlock_state {
2677         uint16_t vwv[8];
2678         uint8_t data[10];
2679 };
2680
2681 static void cli_unlock_done(struct tevent_req *subreq);
2682
2683 struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
2684                                 struct event_context *ev,
2685                                 struct cli_state *cli,
2686                                 uint16_t fnum,
2687                                 uint64_t offset,
2688                                 uint64_t len)
2689
2690 {
2691         struct tevent_req *req = NULL, *subreq = NULL;
2692         struct cli_unlock_state *state = NULL;
2693         uint8_t additional_flags = 0;
2694
2695         req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
2696         if (req == NULL) {
2697                 return NULL;
2698         }
2699
2700         SCVAL(state->vwv+0, 0, 0xFF);
2701         SSVAL(state->vwv+2, 0, fnum);
2702         SCVAL(state->vwv+3, 0, 0);
2703         SIVALS(state->vwv+4, 0, 0);
2704         SSVAL(state->vwv+6, 0, 1);
2705         SSVAL(state->vwv+7, 0, 0);
2706
2707         SSVAL(state->data, 0, cli->pid);
2708         SIVAL(state->data, 2, offset);
2709         SIVAL(state->data, 6, len);
2710
2711         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2712                                 8, state->vwv, 10, state->data);
2713         if (tevent_req_nomem(subreq, req)) {
2714                 return tevent_req_post(req, ev);
2715         }
2716         tevent_req_set_callback(subreq, cli_unlock_done, req);
2717         return req;
2718 }
2719
2720 static void cli_unlock_done(struct tevent_req *subreq)
2721 {
2722         struct tevent_req *req = tevent_req_callback_data(
2723                                 subreq, struct tevent_req);
2724         NTSTATUS status;
2725
2726         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2727         TALLOC_FREE(subreq);
2728         if (!NT_STATUS_IS_OK(status)) {
2729                 tevent_req_nterror(req, status);
2730                 return;
2731         }
2732         tevent_req_done(req);
2733 }
2734
2735 NTSTATUS cli_unlock_recv(struct tevent_req *req)
2736 {
2737         return tevent_req_simple_recv_ntstatus(req);
2738 }
2739
2740 NTSTATUS cli_unlock(struct cli_state *cli,
2741                         uint16_t fnum,
2742                         uint32_t offset,
2743                         uint32_t len)
2744 {
2745         TALLOC_CTX *frame = talloc_stackframe();
2746         struct event_context *ev;
2747         struct tevent_req *req;
2748         NTSTATUS status = NT_STATUS_OK;
2749
2750         if (cli_has_async_calls(cli)) {
2751                 /*
2752                  * Can't use sync call while an async call is in flight
2753                  */
2754                 status = NT_STATUS_INVALID_PARAMETER;
2755                 goto fail;
2756         }
2757
2758         ev = event_context_init(frame);
2759         if (ev == NULL) {
2760                 status = NT_STATUS_NO_MEMORY;
2761                 goto fail;
2762         }
2763
2764         req = cli_unlock_send(frame, ev, cli,
2765                         fnum, offset, len);
2766         if (req == NULL) {
2767                 status = NT_STATUS_NO_MEMORY;
2768                 goto fail;
2769         }
2770
2771         if (!tevent_req_poll(req, ev)) {
2772                 status = map_nt_error_from_unix(errno);
2773                 goto fail;
2774         }
2775
2776         status = cli_unlock_recv(req);
2777
2778  fail:
2779         TALLOC_FREE(frame);
2780         if (!NT_STATUS_IS_OK(status)) {
2781                 cli_set_error(cli, status);
2782         }
2783         return status;
2784 }
2785
2786 /****************************************************************************
2787  Lock a file with 64 bit offsets.
2788 ****************************************************************************/
2789
2790 bool cli_lock64(struct cli_state *cli, uint16_t fnum,
2791                 uint64_t offset, uint64_t len, int timeout, enum brl_type lock_type)
2792 {
2793         char *p;
2794         int saved_timeout = cli->timeout;
2795         int ltype;
2796
2797         if (! (cli->capabilities & CAP_LARGE_FILES)) {
2798                 return cli_lock(cli, fnum, offset, len, timeout, lock_type);
2799         }
2800
2801         ltype = (lock_type == READ_LOCK? 1 : 0);
2802         ltype |= LOCKING_ANDX_LARGE_FILES;
2803
2804         memset(cli->outbuf,'\0',smb_size);
2805         memset(cli->inbuf,'\0', smb_size);
2806
2807         cli_set_message(cli->outbuf,8,0,True);
2808
2809         SCVAL(cli->outbuf,smb_com,SMBlockingX);
2810         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2811         cli_setup_packet(cli);
2812
2813         SCVAL(cli->outbuf,smb_vwv0,0xFF);
2814         SSVAL(cli->outbuf,smb_vwv2,fnum);
2815         SCVAL(cli->outbuf,smb_vwv3,ltype);
2816         SIVALS(cli->outbuf, smb_vwv4, timeout);
2817         SSVAL(cli->outbuf,smb_vwv6,0);
2818         SSVAL(cli->outbuf,smb_vwv7,1);
2819
2820         p = smb_buf(cli->outbuf);
2821         SIVAL(p, 0, cli->pid);
2822         SOFF_T_R(p, 4, offset);
2823         SOFF_T_R(p, 12, len);
2824         p += 20;
2825
2826         cli_setup_bcc(cli, p);
2827         cli_send_smb(cli);
2828
2829         if (timeout != 0) {
2830                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 5*1000);
2831         }
2832
2833         if (!cli_receive_smb(cli)) {
2834                 cli->timeout = saved_timeout;
2835                 return False;
2836         }
2837
2838         cli->timeout = saved_timeout;
2839
2840         if (cli_is_error(cli)) {
2841                 return False;
2842         }
2843
2844         return True;
2845 }
2846
2847 /****************************************************************************
2848  Unlock a file with 64 bit offsets.
2849 ****************************************************************************/
2850
2851 struct cli_unlock64_state {
2852         uint16_t vwv[8];
2853         uint8_t data[20];
2854 };
2855
2856 static void cli_unlock64_done(struct tevent_req *subreq);
2857
2858 struct tevent_req *cli_unlock64_send(TALLOC_CTX *mem_ctx,
2859                                 struct event_context *ev,
2860                                 struct cli_state *cli,
2861                                 uint16_t fnum,
2862                                 uint64_t offset,
2863                                 uint64_t len)
2864
2865 {
2866         struct tevent_req *req = NULL, *subreq = NULL;
2867         struct cli_unlock64_state *state = NULL;
2868         uint8_t additional_flags = 0;
2869
2870         req = tevent_req_create(mem_ctx, &state, struct cli_unlock64_state);
2871         if (req == NULL) {
2872                 return NULL;
2873         }
2874
2875         SCVAL(state->vwv+0, 0, 0xff);
2876         SSVAL(state->vwv+2, 0, fnum);
2877         SCVAL(state->vwv+3, 0,LOCKING_ANDX_LARGE_FILES);
2878         SIVALS(state->vwv+4, 0, 0);
2879         SSVAL(state->vwv+6, 0, 1);
2880         SSVAL(state->vwv+7, 0, 0);
2881
2882         SIVAL(state->data, 0, cli->pid);
2883         SOFF_T_R(state->data, 4, offset);
2884         SOFF_T_R(state->data, 12, len);
2885
2886         subreq = cli_smb_send(state, ev, cli, SMBlockingX, additional_flags,
2887                                 8, state->vwv, 20, state->data);
2888         if (tevent_req_nomem(subreq, req)) {
2889                 return tevent_req_post(req, ev);
2890         }
2891         tevent_req_set_callback(subreq, cli_unlock64_done, req);
2892         return req;
2893 }
2894
2895 static void cli_unlock64_done(struct tevent_req *subreq)
2896 {
2897         struct tevent_req *req = tevent_req_callback_data(
2898                                 subreq, struct tevent_req);
2899         NTSTATUS status;
2900
2901         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2902         TALLOC_FREE(subreq);
2903         if (!NT_STATUS_IS_OK(status)) {
2904                 tevent_req_nterror(req, status);
2905                 return;
2906         }
2907         tevent_req_done(req);
2908 }
2909
2910 NTSTATUS cli_unlock64_recv(struct tevent_req *req)
2911 {
2912         return tevent_req_simple_recv_ntstatus(req);
2913 }
2914
2915 NTSTATUS cli_unlock64(struct cli_state *cli,
2916                                 uint16_t fnum,
2917                                 uint64_t offset,
2918                                 uint64_t len)
2919 {
2920         TALLOC_CTX *frame = talloc_stackframe();
2921         struct event_context *ev;
2922         struct tevent_req *req;
2923         NTSTATUS status = NT_STATUS_OK;
2924
2925         if (! (cli->capabilities & CAP_LARGE_FILES)) {
2926                 return cli_unlock(cli, fnum, offset, len);
2927         }
2928
2929         if (cli_has_async_calls(cli)) {
2930                 /*
2931                  * Can't use sync call while an async call is in flight
2932                  */
2933                 status = NT_STATUS_INVALID_PARAMETER;
2934                 goto fail;
2935         }
2936
2937         ev = event_context_init(frame);
2938         if (ev == NULL) {
2939                 status = NT_STATUS_NO_MEMORY;
2940                 goto fail;
2941         }
2942
2943         req = cli_unlock64_send(frame, ev, cli,
2944                         fnum, offset, len);
2945         if (req == NULL) {
2946                 status = NT_STATUS_NO_MEMORY;
2947                 goto fail;
2948         }
2949
2950         if (!tevent_req_poll(req, ev)) {
2951                 status = map_nt_error_from_unix(errno);
2952                 goto fail;
2953         }
2954
2955         status = cli_unlock64_recv(req);
2956
2957  fail:
2958         TALLOC_FREE(frame);
2959         if (!NT_STATUS_IS_OK(status)) {
2960                 cli_set_error(cli, status);
2961         }
2962         return status;
2963 }
2964
2965 /****************************************************************************
2966  Get/unlock a POSIX lock on a file - internal function.
2967 ****************************************************************************/
2968
2969 struct posix_lock_state {
2970         uint16_t setup;
2971         uint8_t param[4];
2972         uint8_t data[POSIX_LOCK_DATA_SIZE];
2973 };
2974
2975 static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
2976 {
2977         NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, 0, NULL,
2978                                          NULL, 0, NULL, NULL, 0, NULL);
2979         tevent_req_simple_finish_ntstatus(subreq, status);
2980 }
2981
2982 static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
2983                                         struct event_context *ev,
2984                                         struct cli_state *cli,
2985                                         uint16_t fnum,
2986                                         uint64_t offset,
2987                                         uint64_t len,
2988                                         bool wait_lock,
2989                                         enum brl_type lock_type)
2990 {
2991         struct tevent_req *req = NULL, *subreq = NULL;
2992         struct posix_lock_state *state = NULL;
2993
2994         req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
2995         if (req == NULL) {
2996                 return NULL;
2997         }
2998
2999         /* Setup setup word. */
3000         SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
3001
3002         /* Setup param array. */
3003         SSVAL(&state->param, 0, fnum);
3004         SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
3005
3006         /* Setup data array. */
3007         switch (lock_type) {
3008                 case READ_LOCK:
3009                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3010                                 POSIX_LOCK_TYPE_READ);
3011                         break;
3012                 case WRITE_LOCK:
3013                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3014                                 POSIX_LOCK_TYPE_WRITE);
3015                         break;
3016                 case UNLOCK_LOCK:
3017                         SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
3018                                 POSIX_LOCK_TYPE_UNLOCK);
3019                         break;
3020                 default:
3021                         return NULL;
3022         }
3023
3024         if (wait_lock) {
3025                 SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
3026                                 POSIX_LOCK_FLAG_WAIT);
3027         } else {
3028                 SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
3029                                 POSIX_LOCK_FLAG_NOWAIT);
3030         }
3031
3032         SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli->pid);
3033         SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
3034         SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
3035
3036         subreq = cli_trans_send(state,                  /* mem ctx. */
3037                                 ev,                     /* event ctx. */
3038                                 cli,                    /* cli_state. */
3039                                 SMBtrans2,              /* cmd. */
3040                                 NULL,                   /* pipe name. */
3041                                 -1,                     /* fid. */
3042                                 0,                      /* function. */
3043                                 0,                      /* flags. */
3044                                 &state->setup,          /* setup. */
3045                                 1,                      /* num setup uint16_t words. */
3046                                 0,                      /* max returned setup. */
3047                                 state->param,           /* param. */
3048                                 4,                      /* num param. */
3049                                 2,                      /* max returned param. */
3050                                 state->data,            /* data. */
3051                                 POSIX_LOCK_DATA_SIZE,   /* num data. */
3052                                 0);                     /* max returned data. */
3053
3054         if (tevent_req_nomem(subreq, req)) {
3055                 return tevent_req_post(req, ev);
3056         }
3057         tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
3058         return req;
3059 }
3060
3061 /****************************************************************************
3062  POSIX Lock a file.
3063 ****************************************************************************/
3064
3065 struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
3066                                         struct event_context *ev,
3067                                         struct cli_state *cli,
3068                                         uint16_t fnum,
3069                                         uint64_t offset,
3070                                         uint64_t len,
3071                                         bool wait_lock,
3072                                         enum brl_type lock_type)
3073 {
3074         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3075                                         wait_lock, lock_type);
3076 }
3077
3078 NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
3079 {
3080         NTSTATUS status;
3081
3082         if (tevent_req_is_nterror(req, &status)) {
3083                 return status;
3084         }
3085         return NT_STATUS_OK;
3086 }
3087
3088 NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
3089                         uint64_t offset, uint64_t len,
3090                         bool wait_lock, enum brl_type lock_type)
3091 {
3092         TALLOC_CTX *frame = talloc_stackframe();
3093         struct event_context *ev = NULL;
3094         struct tevent_req *req = NULL;
3095         NTSTATUS status = NT_STATUS_OK;
3096
3097         if (cli_has_async_calls(cli)) {
3098                 /*
3099                  * Can't use sync call while an async call is in flight
3100                  */
3101                 status = NT_STATUS_INVALID_PARAMETER;
3102                 goto fail;
3103         }
3104
3105         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
3106                 status = NT_STATUS_INVALID_PARAMETER;
3107                 goto fail;
3108         }
3109
3110         ev = event_context_init(frame);
3111         if (ev == NULL) {
3112                 status = NT_STATUS_NO_MEMORY;
3113                 goto fail;
3114         }
3115
3116         req = cli_posix_lock_send(frame,
3117                                 ev,
3118                                 cli,
3119                                 fnum,
3120                                 offset,
3121                                 len,
3122                                 wait_lock,
3123                                 lock_type);
3124         if (req == NULL) {
3125                 status = NT_STATUS_NO_MEMORY;
3126                 goto fail;
3127         }
3128
3129         if (!tevent_req_poll(req, ev)) {
3130                 status = map_nt_error_from_unix(errno);
3131                 goto fail;
3132         }
3133
3134         status = cli_posix_lock_recv(req);
3135
3136  fail:
3137         TALLOC_FREE(frame);
3138         if (!NT_STATUS_IS_OK(status)) {
3139                 cli_set_error(cli, status);
3140         }
3141         return status;
3142 }
3143
3144 /****************************************************************************
3145  POSIX Unlock a file.
3146 ****************************************************************************/
3147
3148 struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
3149                                         struct event_context *ev,
3150                                         struct cli_state *cli,
3151                                         uint16_t fnum,
3152                                         uint64_t offset,
3153                                         uint64_t len)
3154 {
3155         return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
3156                                         false, UNLOCK_LOCK);
3157 }
3158
3159 NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
3160 {
3161         NTSTATUS status;
3162
3163         if (tevent_req_is_nterror(req, &status)) {
3164                 return status;
3165         }
3166         return NT_STATUS_OK;
3167 }
3168
3169 NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
3170 {
3171         TALLOC_CTX *frame = talloc_stackframe();
3172         struct event_context *ev = NULL;
3173         struct tevent_req *req = NULL;
3174         NTSTATUS status = NT_STATUS_OK;
3175
3176         if (cli_has_async_calls(cli)) {
3177                 /*
3178                  * Can't use sync call while an async call is in flight
3179                  */
3180                 status = NT_STATUS_INVALID_PARAMETER;
3181                 goto fail;
3182         }
3183
3184         ev = event_context_init(frame);
3185         if (ev == NULL) {
3186                 status = NT_STATUS_NO_MEMORY;
3187                 goto fail;
3188         }
3189
3190         req = cli_posix_unlock_send(frame,
3191                                 ev,
3192                                 cli,
3193                                 fnum,
3194                                 offset,
3195                                 len);
3196         if (req == NULL) {
3197                 status = NT_STATUS_NO_MEMORY;
3198                 goto fail;
3199         }
3200
3201         if (!tevent_req_poll(req, ev)) {
3202                 status = map_nt_error_from_unix(errno);
3203                 goto fail;
3204         }
3205
3206         status = cli_posix_unlock_recv(req);
3207
3208  fail:
3209         TALLOC_FREE(frame);
3210         if (!NT_STATUS_IS_OK(status)) {
3211                 cli_set_error(cli, status);
3212         }
3213         return status;
3214 }
3215
3216 /****************************************************************************
3217  Do a SMBgetattrE call.
3218 ****************************************************************************/
3219
3220 static void cli_getattrE_done(struct tevent_req *subreq);
3221
3222 struct cli_getattrE_state {
3223         uint16_t vwv[1];
3224         int zone_offset;
3225         uint16_t attr;
3226         SMB_OFF_T size;
3227         time_t change_time;
3228         time_t access_time;
3229         time_t write_time;
3230 };
3231
3232 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
3233                                 struct event_context *ev,
3234                                 struct cli_state *cli,
3235                                 uint16_t fnum)
3236 {
3237         struct tevent_req *req = NULL, *subreq = NULL;
3238         struct cli_getattrE_state *state = NULL;
3239         uint8_t additional_flags = 0;
3240
3241         req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
3242         if (req == NULL) {
3243                 return NULL;
3244         }
3245
3246         state->zone_offset = cli->serverzone;
3247         SSVAL(state->vwv+0,0,fnum);
3248
3249         subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
3250                               1, state->vwv, 0, NULL);
3251         if (tevent_req_nomem(subreq, req)) {
3252                 return tevent_req_post(req, ev);
3253         }
3254         tevent_req_set_callback(subreq, cli_getattrE_done, req);
3255         return req;
3256 }
3257
3258 static void cli_getattrE_done(struct tevent_req *subreq)
3259 {
3260         struct tevent_req *req = tevent_req_callback_data(
3261                 subreq, struct tevent_req);
3262         struct cli_getattrE_state *state = tevent_req_data(
3263                 req, struct cli_getattrE_state);
3264         uint8_t wct;
3265         uint16_t *vwv = NULL;
3266         NTSTATUS status;
3267
3268         status = cli_smb_recv(subreq, 11, &wct, &vwv, NULL, NULL);
3269         if (!NT_STATUS_IS_OK(status)) {
3270                 tevent_req_nterror(req, status);
3271                 return;
3272         }
3273
3274         state->size = (SMB_OFF_T)IVAL(vwv+6,0);
3275         state->attr = SVAL(vwv+10,0);
3276         state->change_time = make_unix_date2(vwv+0, state->zone_offset);
3277         state->access_time = make_unix_date2(vwv+2, state->zone_offset);
3278         state->write_time = make_unix_date2(vwv+4, state->zone_offset);
3279
3280         TALLOC_FREE(subreq);
3281         tevent_req_done(req);
3282 }
3283
3284 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
3285                         uint16_t *attr,
3286                         SMB_OFF_T *size,
3287                         time_t *change_time,
3288                         time_t *access_time,
3289                         time_t *write_time)
3290 {
3291         struct cli_getattrE_state *state = tevent_req_data(
3292                                 req, struct cli_getattrE_state);
3293         NTSTATUS status;
3294
3295         if (tevent_req_is_nterror(req, &status)) {
3296                 return status;
3297         }
3298         if (attr) {
3299                 *attr = state->attr;
3300         }
3301         if (size) {
3302                 *size = state->size;
3303         }
3304         if (change_time) {
3305                 *change_time = state->change_time;
3306         }
3307         if (access_time) {
3308                 *access_time = state->access_time;
3309         }
3310         if (write_time) {
3311                 *write_time = state->write_time;
3312         }
3313         return NT_STATUS_OK;
3314 }
3315
3316 NTSTATUS cli_getattrE(struct cli_state *cli,
3317                         uint16_t fnum,
3318                         uint16_t *attr,
3319                         SMB_OFF_T *size,
3320                         time_t *change_time,
3321                         time_t *access_time,
3322                         time_t *write_time)
3323 {
3324         TALLOC_CTX *frame = talloc_stackframe();
3325         struct event_context *ev = NULL;
3326         struct tevent_req *req = NULL;
3327         NTSTATUS status = NT_STATUS_OK;
3328
3329         if (cli_has_async_calls(cli)) {
3330                 /*
3331                  * Can't use sync call while an async call is in flight
3332                  */
3333                 status = NT_STATUS_INVALID_PARAMETER;
3334                 goto fail;
3335         }
3336
3337         ev = event_context_init(frame);
3338         if (ev == NULL) {
3339                 status = NT_STATUS_NO_MEMORY;
3340                 goto fail;
3341         }
3342
3343         req = cli_getattrE_send(frame, ev, cli, fnum);
3344         if (req == NULL) {
3345                 status = NT_STATUS_NO_MEMORY;
3346                 goto fail;
3347         }
3348
3349         if (!tevent_req_poll(req, ev)) {
3350                 status = map_nt_error_from_unix(errno);
3351                 goto fail;
3352         }
3353
3354         status = cli_getattrE_recv(req,
3355                                         attr,
3356                                         size,
3357                                         change_time,
3358                                         access_time,
3359                                         write_time);
3360
3361  fail:
3362         TALLOC_FREE(frame);
3363         if (!NT_STATUS_IS_OK(status)) {
3364                 cli_set_error(cli, status);
3365         }
3366         return status;
3367 }
3368
3369 /****************************************************************************
3370  Do a SMBgetatr call
3371 ****************************************************************************/
3372
3373 static void cli_getatr_done(struct tevent_req *subreq);
3374
3375 struct cli_getatr_state {
3376         int zone_offset;
3377         uint16_t attr;
3378         SMB_OFF_T size;
3379         time_t write_time;
3380 };
3381
3382 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
3383                                 struct event_context *ev,
3384                                 struct cli_state *cli,
3385                                 const char *fname)
3386 {
3387         struct tevent_req *req = NULL, *subreq = NULL;
3388         struct cli_getatr_state *state = NULL;
3389         uint8_t additional_flags = 0;
3390         uint8_t *bytes = NULL;
3391
3392         req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
3393         if (req == NULL) {
3394                 return NULL;
3395         }
3396
3397         state->zone_offset = cli->serverzone;
3398
3399         bytes = talloc_array(state, uint8_t, 1);
3400         if (tevent_req_nomem(bytes, req)) {
3401                 return tevent_req_post(req, ev);
3402         }
3403         bytes[0] = 4;
3404         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
3405                                    strlen(fname)+1, NULL);
3406
3407         if (tevent_req_nomem(bytes, req)) {
3408                 return tevent_req_post(req, ev);
3409         }
3410
3411         subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
3412                               0, NULL, talloc_get_size(bytes), bytes);
3413         if (tevent_req_nomem(subreq, req)) {
3414                 return tevent_req_post(req, ev);
3415         }
3416         tevent_req_set_callback(subreq, cli_getatr_done, req);
3417         return req;
3418 }
3419
3420 static void cli_getatr_done(struct tevent_req *subreq)
3421 {
3422         struct tevent_req *req = tevent_req_callback_data(
3423                 subreq, struct tevent_req);
3424         struct cli_getatr_state *state = tevent_req_data(
3425                 req, struct cli_getatr_state);
3426         uint8_t wct;
3427         uint16_t *vwv = NULL;
3428         NTSTATUS status;
3429
3430         status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL);
3431         if (!NT_STATUS_IS_OK(status)) {
3432                 tevent_req_nterror(req, status);
3433                 return;
3434         }
3435
3436         state->attr = SVAL(vwv+0,0);
3437         state->size = (SMB_OFF_T)IVAL(vwv+3,0);
3438         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
3439
3440         TALLOC_FREE(subreq);
3441         tevent_req_done(req);
3442 }
3443
3444 NTSTATUS cli_getatr_recv(struct tevent_req *req,
3445                         uint16_t *attr,
3446                         SMB_OFF_T *size,
3447                         time_t *write_time)
3448 {
3449         struct cli_getatr_state *state = tevent_req_data(
3450                                 req, struct cli_getatr_state);
3451         NTSTATUS status;
3452
3453         if (tevent_req_is_nterror(req, &status)) {
3454                 return status;
3455         }
3456         if (attr) {
3457                 *attr = state->attr;
3458         }
3459         if (size) {
3460                 *size = state->size;
3461         }
3462         if (write_time) {
3463                 *write_time = state->write_time;
3464         }
3465         return NT_STATUS_OK;
3466 }
3467
3468 NTSTATUS cli_getatr(struct cli_state *cli,
3469                         const char *fname,
3470                         uint16_t *attr,
3471                         SMB_OFF_T *size,
3472                         time_t *write_time)
3473 {
3474         TALLOC_CTX *frame = talloc_stackframe();
3475         struct event_context *ev = NULL;
3476         struct tevent_req *req = NULL;
3477         NTSTATUS status = NT_STATUS_OK;
3478
3479         if (cli_has_async_calls(cli)) {
3480                 /*
3481                  * Can't use sync call while an async call is in flight
3482                  */
3483                 status = NT_STATUS_INVALID_PARAMETER;
3484                 goto fail;
3485         }
3486
3487         ev = event_context_init(frame);
3488         if (ev == NULL) {
3489                 status = NT_STATUS_NO_MEMORY;
3490                 goto fail;
3491         }
3492
3493         req = cli_getatr_send(frame, ev, cli, fname);
3494         if (req == NULL) {
3495                 status = NT_STATUS_NO_MEMORY;
3496                 goto fail;
3497         }
3498
3499         if (!tevent_req_poll(req, ev)) {
3500                 status = map_nt_error_from_unix(errno);
3501                 goto fail;
3502         }
3503
3504         status = cli_getatr_recv(req,
3505                                 attr,
3506                                 size,
3507                                 write_time);
3508
3509  fail:
3510         TALLOC_FREE(frame);
3511         if (!NT_STATUS_IS_OK(status)) {
3512                 cli_set_error(cli, status);
3513         }
3514         return status;
3515 }
3516
3517 /****************************************************************************
3518  Do a SMBsetattrE call.
3519 ****************************************************************************/
3520
3521 static void cli_setattrE_done(struct tevent_req *subreq);
3522
3523 struct cli_setattrE_state {
3524         uint16_t vwv[7];
3525 };
3526
3527 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
3528                                 struct event_context *ev,
3529                                 struct cli_state *cli,
3530                                 uint16_t fnum,
3531                                 time_t change_time,
3532                                 time_t access_time,
3533                                 time_t write_time)
3534 {
3535         struct tevent_req *req = NULL, *subreq = NULL;
3536         struct cli_setattrE_state *state = NULL;
3537         uint8_t additional_flags = 0;
3538
3539         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
3540         if (req == NULL) {
3541                 return NULL;
3542         }
3543
3544         SSVAL(state->vwv+0, 0, fnum);
3545         cli_put_dos_date2(cli, (char *)&state->vwv[1], 0, change_time);
3546         cli_put_dos_date2(cli, (char *)&state->vwv[3], 0, access_time);
3547         cli_put_dos_date2(cli, (char *)&state->vwv[5], 0, write_time);
3548
3549         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
3550                               7, state->vwv, 0, NULL);
3551         if (tevent_req_nomem(subreq, req)) {
3552                 return tevent_req_post(req, ev);
3553         }
3554         tevent_req_set_callback(subreq, cli_setattrE_done, req);
3555         return req;
3556 }
3557
3558 static void cli_setattrE_done(struct tevent_req *subreq)
3559 {
3560         struct tevent_req *req = tevent_req_callback_data(
3561                 subreq, struct tevent_req);
3562         NTSTATUS status;
3563
3564         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
3565         TALLOC_FREE(subreq);
3566         if (!NT_STATUS_IS_OK(status)) {
3567                 tevent_req_nterror(req, status);
3568                 return;
3569         }
3570         tevent_req_done(req);
3571 }
3572
3573 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
3574 {
3575         return tevent_req_simple_recv_ntstatus(req);
3576 }
3577
3578 NTSTATUS cli_setattrE(struct cli_state *cli,
3579                         uint16_t fnum,
3580                         time_t change_time,
3581                         time_t access_time,
3582                         time_t write_time)
3583 {
3584         TALLOC_CTX *frame = talloc_stackframe();
3585         struct event_context *ev = NULL;
3586         struct tevent_req *req = NULL;
3587         NTSTATUS status = NT_STATUS_OK;
3588
3589         if (cli_has_async_calls(cli)) {
3590                 /*
3591                  * Can't use sync call while an async call is in flight
3592                  */
3593                 status = NT_STATUS_INVALID_PARAMETER;
3594                 goto fail;
3595         }
3596
3597         ev = event_context_init(frame);
3598         if (ev == NULL) {
3599                 status = NT_STATUS_NO_MEMORY;
3600                 goto fail;
3601         }
3602
3603         req = cli_setattrE_send(frame, ev,
3604                         cli,
3605                         fnum,
3606                         change_time,
3607                         access_time,
3608                         write_time);
3609
3610         if (req == NULL) {
3611                 status = NT_STATUS_NO_MEMORY;
3612                 goto fail;