s3:libsmb: fix layering of cli_ntrename_internal and its callers
[ira/wip.git] / source3 / libsmb / clifile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client file operations
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Jeremy Allison 2001-2009
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 /****************************************************************************
24  Hard/Symlink a file (UNIX extensions).
25  Creates new name (sym)linked to oldname.
26 ****************************************************************************/
27
28 static bool cli_link_internal(struct cli_state *cli, const char *oldname, const char *newname, bool hard_link)
29 {
30         unsigned int data_len = 0;
31         unsigned int param_len = 0;
32         uint16_t setup = TRANSACT2_SETPATHINFO;
33         char *param;
34         char *data;
35         char *rparam=NULL, *rdata=NULL;
36         char *p;
37         size_t oldlen = 2*(strlen(oldname)+1);
38         size_t newlen = 2*(strlen(newname)+1);
39
40         param = SMB_MALLOC_ARRAY(char, 6+newlen+2);
41
42         if (!param) {
43                 return false;
44         }
45
46         data = SMB_MALLOC_ARRAY(char, oldlen+2);
47
48         if (!data) {
49                 SAFE_FREE(param);
50                 return false;
51         }
52
53         SSVAL(param,0,hard_link ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
54         SIVAL(param,2,0);
55         p = &param[6];
56
57         p += clistr_push(cli, p, newname, newlen, STR_TERMINATE);
58         param_len = PTR_DIFF(p, param);
59
60         p = data;
61         p += clistr_push(cli, p, oldname, oldlen, STR_TERMINATE);
62         data_len = PTR_DIFF(p, data);
63
64         if (!cli_send_trans(cli, SMBtrans2,
65                         NULL,                        /* name */
66                         -1, 0,                          /* fid, flags */
67                         &setup, 1, 0,                   /* setup, length, max */
68                         param, param_len, 2,            /* param, length, max */
69                         data,  data_len, cli->max_xmit /* data, length, max */
70                         )) {
71                 SAFE_FREE(data);
72                 SAFE_FREE(param);
73                 return false;
74         }
75
76         SAFE_FREE(data);
77         SAFE_FREE(param);
78
79         if (!cli_receive_trans(cli, SMBtrans2,
80                         &rparam, &param_len,
81                         &rdata, &data_len)) {
82                         return false;
83         }
84
85         SAFE_FREE(data);
86         SAFE_FREE(param);
87         SAFE_FREE(rdata);
88         SAFE_FREE(rparam);
89
90         return true;
91 }
92
93 /****************************************************************************
94  Map standard UNIX permissions onto wire representations.
95 ****************************************************************************/
96
97 uint32_t unix_perms_to_wire(mode_t perms)
98 {
99         unsigned int ret = 0;
100
101         ret |= ((perms & S_IXOTH) ?  UNIX_X_OTH : 0);
102         ret |= ((perms & S_IWOTH) ?  UNIX_W_OTH : 0);
103         ret |= ((perms & S_IROTH) ?  UNIX_R_OTH : 0);
104         ret |= ((perms & S_IXGRP) ?  UNIX_X_GRP : 0);
105         ret |= ((perms & S_IWGRP) ?  UNIX_W_GRP : 0);
106         ret |= ((perms & S_IRGRP) ?  UNIX_R_GRP : 0);
107         ret |= ((perms & S_IXUSR) ?  UNIX_X_USR : 0);
108         ret |= ((perms & S_IWUSR) ?  UNIX_W_USR : 0);
109         ret |= ((perms & S_IRUSR) ?  UNIX_R_USR : 0);
110 #ifdef S_ISVTX
111         ret |= ((perms & S_ISVTX) ?  UNIX_STICKY : 0);
112 #endif
113 #ifdef S_ISGID
114         ret |= ((perms & S_ISGID) ?  UNIX_SET_GID : 0);
115 #endif
116 #ifdef S_ISUID
117         ret |= ((perms & S_ISUID) ?  UNIX_SET_UID : 0);
118 #endif
119         return ret;
120 }
121
122 /****************************************************************************
123  Map wire permissions to standard UNIX.
124 ****************************************************************************/
125
126 mode_t wire_perms_to_unix(uint32_t perms)
127 {
128         mode_t ret = (mode_t)0;
129
130         ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
131         ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
132         ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
133         ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
134         ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
135         ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
136         ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
137         ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
138         ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
139 #ifdef S_ISVTX
140         ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
141 #endif
142 #ifdef S_ISGID
143         ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
144 #endif
145 #ifdef S_ISUID
146         ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
147 #endif
148         return ret;
149 }
150
151 /****************************************************************************
152  Return the file type from the wire filetype for UNIX extensions.
153 ****************************************************************************/
154
155 static mode_t unix_filetype_from_wire(uint32_t wire_type)
156 {
157         switch (wire_type) {
158                 case UNIX_TYPE_FILE:
159                         return S_IFREG;
160                 case UNIX_TYPE_DIR:
161                         return S_IFDIR;
162 #ifdef S_IFLNK
163                 case UNIX_TYPE_SYMLINK:
164                         return S_IFLNK;
165 #endif
166 #ifdef S_IFCHR
167                 case UNIX_TYPE_CHARDEV:
168                         return S_IFCHR;
169 #endif
170 #ifdef S_IFBLK
171                 case UNIX_TYPE_BLKDEV:
172                         return S_IFBLK;
173 #endif
174 #ifdef S_IFIFO
175                 case UNIX_TYPE_FIFO:
176                         return S_IFIFO;
177 #endif
178 #ifdef S_IFSOCK
179                 case UNIX_TYPE_SOCKET:
180                         return S_IFSOCK;
181 #endif
182                 default:
183                         return (mode_t)0;
184         }
185 }
186
187 /****************************************************************************
188  Do a POSIX getfacl (UNIX extensions).
189 ****************************************************************************/
190
191 bool cli_unix_getfacl(struct cli_state *cli, const char *name, size_t *prb_size, char **retbuf)
192 {
193         unsigned int param_len = 0;
194         unsigned int data_len = 0;
195         uint16_t setup = TRANSACT2_QPATHINFO;
196         char *param;
197         size_t nlen = 2*(strlen(name)+1);
198         char *rparam=NULL, *rdata=NULL;
199         char *p;
200
201         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
202         if (!param) {
203                 return false;
204         }
205
206         p = param;
207         memset(p, '\0', 6);
208         SSVAL(p, 0, SMB_QUERY_POSIX_ACL);
209         p += 6;
210         p += clistr_push(cli, p, name, nlen, STR_TERMINATE);
211         param_len = PTR_DIFF(p, param);
212
213         if (!cli_send_trans(cli, SMBtrans2,
214                 NULL,                        /* name */
215                 -1, 0,                       /* fid, flags */
216                 &setup, 1, 0,                /* setup, length, max */
217                 param, param_len, 2,         /* param, length, max */
218                 NULL,  0, cli->max_xmit      /* data, length, max */
219                 )) {
220                 SAFE_FREE(param);
221                 return false;
222         }
223
224         SAFE_FREE(param);
225
226         if (!cli_receive_trans(cli, SMBtrans2,
227                         &rparam, &param_len,
228                         &rdata, &data_len)) {
229                 return false;
230         }
231
232         if (data_len < 6) {
233                 SAFE_FREE(rdata);
234                 SAFE_FREE(rparam);
235                 return false;
236         }
237
238         SAFE_FREE(rparam);
239         *retbuf = rdata;
240         *prb_size = (size_t)data_len;
241
242         return true;
243 }
244
245 /****************************************************************************
246  Stat a file (UNIX extensions).
247 ****************************************************************************/
248
249 bool cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf)
250 {
251         unsigned int param_len = 0;
252         unsigned int data_len = 0;
253         uint16_t setup = TRANSACT2_QPATHINFO;
254         char *param;
255         size_t nlen = 2*(strlen(name)+1);
256         char *rparam=NULL, *rdata=NULL;
257         char *p;
258
259         ZERO_STRUCTP(sbuf);
260
261         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
262         if (!param) {
263                 return false;
264         }
265         p = param;
266         memset(p, '\0', 6);
267         SSVAL(p, 0, SMB_QUERY_FILE_UNIX_BASIC);
268         p += 6;
269         p += clistr_push(cli, p, name, nlen, STR_TERMINATE);
270         param_len = PTR_DIFF(p, param);
271
272         if (!cli_send_trans(cli, SMBtrans2,
273                         NULL,                        /* name */
274                         -1, 0,                       /* fid, flags */
275                         &setup, 1, 0,                /* setup, length, max */
276                         param, param_len, 2,         /* param, length, max */
277                         NULL,  0, cli->max_xmit      /* data, length, max */
278                         )) {
279                 SAFE_FREE(param);
280                 return false;
281         }
282
283         SAFE_FREE(param);
284
285         if (!cli_receive_trans(cli, SMBtrans2,
286                         &rparam, &param_len,
287                         &rdata, &data_len)) {
288                 return false;
289         }
290
291         if (data_len < 96) {
292                 SAFE_FREE(rdata);
293                 SAFE_FREE(rparam);
294                 return false;
295         }
296
297         sbuf->st_size = IVAL2_TO_SMB_BIG_UINT(rdata,0);     /* total size, in bytes */
298         sbuf->st_blocks = IVAL2_TO_SMB_BIG_UINT(rdata,8);   /* number of blocks allocated */
299 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
300         sbuf->st_blocks /= STAT_ST_BLOCKSIZE;
301 #else
302         /* assume 512 byte blocks */
303         sbuf->st_blocks /= 512;
304 #endif
305         set_ctimespec(sbuf, interpret_long_date(rdata + 16));    /* time of last change */
306         set_atimespec(sbuf, interpret_long_date(rdata + 24));    /* time of last access */
307         set_mtimespec(sbuf, interpret_long_date(rdata + 32));    /* time of last modification */
308
309         sbuf->st_uid = (uid_t) IVAL(rdata,40);      /* user ID of owner */
310         sbuf->st_gid = (gid_t) IVAL(rdata,48);      /* group ID of owner */
311         sbuf->st_mode |= unix_filetype_from_wire(IVAL(rdata, 56));
312 #if defined(HAVE_MAKEDEV)
313         {
314                 uint32_t dev_major = IVAL(rdata,60);
315                 uint32_t dev_minor = IVAL(rdata,68);
316                 sbuf->st_rdev = makedev(dev_major, dev_minor);
317         }
318 #endif
319         sbuf->st_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(rdata,76);      /* inode */
320         sbuf->st_mode |= wire_perms_to_unix(IVAL(rdata,84));     /* protection */
321         sbuf->st_nlink = IVAL(rdata,92);    /* number of hard links */
322
323         SAFE_FREE(rdata);
324         SAFE_FREE(rparam);
325
326         return true;
327 }
328
329 /****************************************************************************
330  Symlink a file (UNIX extensions).
331 ****************************************************************************/
332
333 bool cli_unix_symlink(struct cli_state *cli, const char *oldname, const char *newname)
334 {
335         return cli_link_internal(cli, oldname, newname, False);
336 }
337
338 /****************************************************************************
339  Hard a file (UNIX extensions).
340 ****************************************************************************/
341
342 bool cli_unix_hardlink(struct cli_state *cli, const char *oldname, const char *newname)
343 {
344         return cli_link_internal(cli, oldname, newname, True);
345 }
346
347 /****************************************************************************
348  Chmod or chown a file internal (UNIX extensions).
349 ****************************************************************************/
350
351 static bool cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname, uint32_t mode, uint32_t uid, uint32_t gid)
352 {
353         unsigned int data_len = 0;
354         unsigned int param_len = 0;
355         uint16_t setup = TRANSACT2_SETPATHINFO;
356         size_t nlen = 2*(strlen(fname)+1);
357         char *param;
358         char data[100];
359         char *rparam=NULL, *rdata=NULL;
360         char *p;
361
362         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
363         if (!param) {
364                 return false;
365         }
366         memset(param, '\0', 6);
367         memset(data, 0, sizeof(data));
368
369         SSVAL(param,0,SMB_SET_FILE_UNIX_BASIC);
370         p = &param[6];
371
372         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
373         param_len = PTR_DIFF(p, param);
374
375         memset(data, 0xff, 40); /* Set all sizes/times to no change. */
376
377         SIVAL(data,40,uid);
378         SIVAL(data,48,gid);
379         SIVAL(data,84,mode);
380
381         data_len = 100;
382
383         if (!cli_send_trans(cli, SMBtrans2,
384                         NULL,                        /* name */
385                         -1, 0,                          /* fid, flags */
386                         &setup, 1, 0,                   /* setup, length, max */
387                         param, param_len, 2,            /* param, length, max */
388                         (char *)&data,  data_len, cli->max_xmit /* data, length, max */
389                         )) {
390                 SAFE_FREE(param);
391                 return False;
392         }
393
394         SAFE_FREE(param);
395
396         if (!cli_receive_trans(cli, SMBtrans2,
397                         &rparam, &param_len,
398                         &rdata, &data_len)) {
399                 return false;
400         }
401
402         SAFE_FREE(rdata);
403         SAFE_FREE(rparam);
404
405         return true;
406 }
407
408 /****************************************************************************
409  chmod a file (UNIX extensions).
410 ****************************************************************************/
411
412 bool cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
413 {
414         return cli_unix_chmod_chown_internal(cli, fname,
415                 unix_perms_to_wire(mode), SMB_UID_NO_CHANGE, SMB_GID_NO_CHANGE);
416 }
417
418 /****************************************************************************
419  chown a file (UNIX extensions).
420 ****************************************************************************/
421
422 bool cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid)
423 {
424         return cli_unix_chmod_chown_internal(cli, fname,
425                         SMB_MODE_NO_CHANGE, (uint32)uid, (uint32)gid);
426 }
427
428 /****************************************************************************
429  Rename a file.
430 ****************************************************************************/
431
432 static void cli_rename_done(struct tevent_req *subreq);
433
434 struct cli_rename_state {
435         uint16_t vwv[1];
436 };
437
438 struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
439                                 struct event_context *ev,
440                                 struct cli_state *cli,
441                                 const char *fname_src,
442                                 const char *fname_dst)
443 {
444         struct tevent_req *req = NULL, *subreq = NULL;
445         struct cli_rename_state *state = NULL;
446         uint8_t additional_flags = 0;
447         uint8_t *bytes = NULL;
448
449         req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
450         if (req == NULL) {
451                 return NULL;
452         }
453
454         SSVAL(state->vwv+0, 0, aSYSTEM | aHIDDEN | aDIR);
455
456         bytes = talloc_array(state, uint8_t, 1);
457         if (tevent_req_nomem(bytes, req)) {
458                 return tevent_req_post(req, ev);
459         }
460         bytes[0] = 4;
461         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
462                                    strlen(fname_src)+1, NULL);
463         if (tevent_req_nomem(bytes, req)) {
464                 return tevent_req_post(req, ev);
465         }
466
467         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
468                         talloc_get_size(bytes)+1);
469         if (tevent_req_nomem(bytes, req)) {
470                 return tevent_req_post(req, ev);
471         }
472
473         bytes[talloc_get_size(bytes)-1] = 4;
474         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
475                                    strlen(fname_dst)+1, NULL);
476         if (tevent_req_nomem(bytes, req)) {
477                 return tevent_req_post(req, ev);
478         }
479
480         subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
481                               1, state->vwv, talloc_get_size(bytes), bytes);
482         if (tevent_req_nomem(subreq, req)) {
483                 return tevent_req_post(req, ev);
484         }
485         tevent_req_set_callback(subreq, cli_rename_done, req);
486         return req;
487 }
488
489 static void cli_rename_done(struct tevent_req *subreq)
490 {
491         struct tevent_req *req = tevent_req_callback_data(
492                                 subreq, struct tevent_req);
493         NTSTATUS status;
494
495         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
496         TALLOC_FREE(subreq);
497         if (!NT_STATUS_IS_OK(status)) {
498                 tevent_req_nterror(req, status);
499                 return;
500         }
501         tevent_req_done(req);
502 }
503
504 NTSTATUS cli_rename_recv(struct tevent_req *req)
505 {
506         return tevent_req_simple_recv_ntstatus(req);
507 }
508
509 NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
510 {
511         TALLOC_CTX *frame = talloc_stackframe();
512         struct event_context *ev;
513         struct tevent_req *req;
514         NTSTATUS status = NT_STATUS_OK;
515
516         if (cli_has_async_calls(cli)) {
517                 /*
518                  * Can't use sync call while an async call is in flight
519                  */
520                 status = NT_STATUS_INVALID_PARAMETER;
521                 goto fail;
522         }
523
524         ev = event_context_init(frame);
525         if (ev == NULL) {
526                 status = NT_STATUS_NO_MEMORY;
527                 goto fail;
528         }
529
530         req = cli_rename_send(frame, ev, cli, fname_src, fname_dst);
531         if (req == NULL) {
532                 status = NT_STATUS_NO_MEMORY;
533                 goto fail;
534         }
535
536         if (!tevent_req_poll(req, ev)) {
537                 status = map_nt_error_from_unix(errno);
538                 goto fail;
539         }
540
541         status = cli_rename_recv(req);
542
543  fail:
544         TALLOC_FREE(frame);
545         if (!NT_STATUS_IS_OK(status)) {
546                 cli_set_error(cli, status);
547         }
548         return status;
549 }
550
551 /****************************************************************************
552  NT Rename a file.
553 ****************************************************************************/
554
555 static void cli_ntrename_internal_done(struct tevent_req *subreq);
556
557 struct cli_ntrename_internal_state {
558         uint16_t vwv[4];
559 };
560
561 static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
562                                 struct event_context *ev,
563                                 struct cli_state *cli,
564                                 const char *fname_src,
565                                 const char *fname_dst,
566                                 uint16_t rename_flag)
567 {
568         struct tevent_req *req = NULL, *subreq = NULL;
569         struct cli_ntrename_internal_state *state = NULL;
570         uint8_t additional_flags = 0;
571         uint8_t *bytes = NULL;
572
573         req = tevent_req_create(mem_ctx, &state,
574                                 struct cli_ntrename_internal_state);
575         if (req == NULL) {
576                 return NULL;
577         }
578
579         SSVAL(state->vwv+0, 0 ,aSYSTEM | aHIDDEN | aDIR);
580         SSVAL(state->vwv+1, 0, rename_flag);
581
582         bytes = talloc_array(state, uint8_t, 1);
583         if (tevent_req_nomem(bytes, req)) {
584                 return tevent_req_post(req, ev);
585         }
586         bytes[0] = 4;
587         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_src,
588                                    strlen(fname_src)+1, NULL);
589         if (tevent_req_nomem(bytes, req)) {
590                 return tevent_req_post(req, ev);
591         }
592
593         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
594                         talloc_get_size(bytes)+1);
595         if (tevent_req_nomem(bytes, req)) {
596                 return tevent_req_post(req, ev);
597         }
598
599         bytes[talloc_get_size(bytes)-1] = 4;
600         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname_dst,
601                                    strlen(fname_dst)+1, NULL);
602         if (tevent_req_nomem(bytes, req)) {
603                 return tevent_req_post(req, ev);
604         }
605
606         subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
607                               4, state->vwv, talloc_get_size(bytes), bytes);
608         if (tevent_req_nomem(subreq, req)) {
609                 return tevent_req_post(req, ev);
610         }
611         tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
612         return req;
613 }
614
615 static void cli_ntrename_internal_done(struct tevent_req *subreq)
616 {
617         struct tevent_req *req = tevent_req_callback_data(
618                                 subreq, struct tevent_req);
619         NTSTATUS status;
620
621         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
622         TALLOC_FREE(subreq);
623         if (!NT_STATUS_IS_OK(status)) {
624                 tevent_req_nterror(req, status);
625                 return;
626         }
627         tevent_req_done(req);
628 }
629
630 static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
631 {
632         return tevent_req_simple_recv_ntstatus(req);
633 }
634
635 struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
636                                 struct event_context *ev,
637                                 struct cli_state *cli,
638                                 const char *fname_src,
639                                 const char *fname_dst)
640 {
641         return cli_ntrename_internal_send(mem_ctx,
642                                           ev,
643                                           cli,
644                                           fname_src,
645                                           fname_dst,
646                                           RENAME_FLAG_RENAME);
647 }
648
649 NTSTATUS cli_ntrename_recv(struct tevent_req *req)
650 {
651         return cli_ntrename_internal_recv(req);
652 }
653
654 NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
655 {
656         TALLOC_CTX *frame = talloc_stackframe();
657         struct event_context *ev;
658         struct tevent_req *req;
659         NTSTATUS status = NT_STATUS_OK;
660
661         if (cli_has_async_calls(cli)) {
662                 /*
663                  * Can't use sync call while an async call is in flight
664                  */
665                 status = NT_STATUS_INVALID_PARAMETER;
666                 goto fail;
667         }
668
669         ev = event_context_init(frame);
670         if (ev == NULL) {
671                 status = NT_STATUS_NO_MEMORY;
672                 goto fail;
673         }
674
675         req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
676         if (req == NULL) {
677                 status = NT_STATUS_NO_MEMORY;
678                 goto fail;
679         }
680
681         if (!tevent_req_poll(req, ev)) {
682                 status = map_nt_error_from_unix(errno);
683                 goto fail;
684         }
685
686         status = cli_ntrename_recv(req);
687
688  fail:
689         TALLOC_FREE(frame);
690         if (!NT_STATUS_IS_OK(status)) {
691                 cli_set_error(cli, status);
692         }
693         return status;
694 }
695
696 /****************************************************************************
697  NT hardlink a file.
698 ****************************************************************************/
699
700 struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
701                                 struct event_context *ev,
702                                 struct cli_state *cli,
703                                 const char *fname_src,
704                                 const char *fname_dst)
705 {
706         return cli_ntrename_internal_send(mem_ctx,
707                                           ev,
708                                           cli,
709                                           fname_src,
710                                           fname_dst,
711                                           RENAME_FLAG_HARD_LINK);
712 }
713
714 NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
715 {
716         return cli_ntrename_internal_recv(req);
717 }
718
719 NTSTATUS cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
720 {
721         TALLOC_CTX *frame = talloc_stackframe();
722         struct event_context *ev;
723         struct tevent_req *req;
724         NTSTATUS status = NT_STATUS_OK;
725
726         if (cli_has_async_calls(cli)) {
727                 /*
728                  * Can't use sync call while an async call is in flight
729                  */
730                 status = NT_STATUS_INVALID_PARAMETER;
731                 goto fail;
732         }
733
734         ev = event_context_init(frame);
735         if (ev == NULL) {
736                 status = NT_STATUS_NO_MEMORY;
737                 goto fail;
738         }
739
740         req = cli_nt_hardlink_send(frame, ev, cli, fname_src, fname_dst);
741         if (req == NULL) {
742                 status = NT_STATUS_NO_MEMORY;
743                 goto fail;
744         }
745
746         if (!tevent_req_poll(req, ev)) {
747                 status = map_nt_error_from_unix(errno);
748                 goto fail;
749         }
750
751         status = cli_nt_hardlink_recv(req);
752
753  fail:
754         TALLOC_FREE(frame);
755         if (!NT_STATUS_IS_OK(status)) {
756                 cli_set_error(cli, status);
757         }
758         return status;
759 }
760
761 /****************************************************************************
762  Delete a file.
763 ****************************************************************************/
764
765 static void cli_unlink_done(struct tevent_req *subreq);
766
767 struct cli_unlink_state {
768         uint16_t vwv[1];
769 };
770
771 struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
772                                 struct event_context *ev,
773                                 struct cli_state *cli,
774                                 const char *fname,
775                                 uint16_t mayhave_attrs)
776 {
777         struct tevent_req *req = NULL, *subreq = NULL;
778         struct cli_unlink_state *state = NULL;
779         uint8_t additional_flags = 0;
780         uint8_t *bytes = NULL;
781
782         req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
783         if (req == NULL) {
784                 return NULL;
785         }
786
787         SSVAL(state->vwv+0, 0, mayhave_attrs);
788
789         bytes = talloc_array(state, uint8_t, 1);
790         if (tevent_req_nomem(bytes, req)) {
791                 return tevent_req_post(req, ev);
792         }
793         bytes[0] = 4;
794         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
795                                    strlen(fname)+1, NULL);
796
797         if (tevent_req_nomem(bytes, req)) {
798                 return tevent_req_post(req, ev);
799         }
800
801         subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
802                                 1, state->vwv, talloc_get_size(bytes), bytes);
803         if (tevent_req_nomem(subreq, req)) {
804                 return tevent_req_post(req, ev);
805         }
806         tevent_req_set_callback(subreq, cli_unlink_done, req);
807         return req;
808 }
809
810 static void cli_unlink_done(struct tevent_req *subreq)
811 {
812         struct tevent_req *req = tevent_req_callback_data(
813                 subreq, struct tevent_req);
814         NTSTATUS status;
815
816         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
817         TALLOC_FREE(subreq);
818         if (!NT_STATUS_IS_OK(status)) {
819                 tevent_req_nterror(req, status);
820                 return;
821         }
822         tevent_req_done(req);
823 }
824
825 NTSTATUS cli_unlink_recv(struct tevent_req *req)
826 {
827         return tevent_req_simple_recv_ntstatus(req);
828 }
829
830 NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs)
831 {
832         TALLOC_CTX *frame = talloc_stackframe();
833         struct event_context *ev;
834         struct tevent_req *req;
835         NTSTATUS status = NT_STATUS_OK;
836
837         if (cli_has_async_calls(cli)) {
838                 /*
839                  * Can't use sync call while an async call is in flight
840                  */
841                 status = NT_STATUS_INVALID_PARAMETER;
842                 goto fail;
843         }
844
845         ev = event_context_init(frame);
846         if (ev == NULL) {
847                 status = NT_STATUS_NO_MEMORY;
848                 goto fail;
849         }
850
851         req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
852         if (req == NULL) {
853                 status = NT_STATUS_NO_MEMORY;
854                 goto fail;
855         }
856
857         if (!tevent_req_poll(req, ev)) {
858                 status = map_nt_error_from_unix(errno);
859                 goto fail;
860         }
861
862         status = cli_unlink_recv(req);
863
864  fail:
865         TALLOC_FREE(frame);
866         if (!NT_STATUS_IS_OK(status)) {
867                 cli_set_error(cli, status);
868         }
869         return status;
870 }
871
872 /****************************************************************************
873  Create a directory.
874 ****************************************************************************/
875
876 static void cli_mkdir_done(struct tevent_req *subreq);
877
878 struct cli_mkdir_state {
879         int dummy;
880 };
881
882 struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
883                                   struct event_context *ev,
884                                   struct cli_state *cli,
885                                   const char *dname)
886 {
887         struct tevent_req *req = NULL, *subreq = NULL;
888         struct cli_mkdir_state *state = NULL;
889         uint8_t additional_flags = 0;
890         uint8_t *bytes = NULL;
891
892         req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
893         if (req == NULL) {
894                 return NULL;
895         }
896
897         bytes = talloc_array(state, uint8_t, 1);
898         if (tevent_req_nomem(bytes, req)) {
899                 return tevent_req_post(req, ev);
900         }
901         bytes[0] = 4;
902         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
903                                    strlen(dname)+1, NULL);
904
905         if (tevent_req_nomem(bytes, req)) {
906                 return tevent_req_post(req, ev);
907         }
908
909         subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
910                               0, NULL, talloc_get_size(bytes), bytes);
911         if (tevent_req_nomem(subreq, req)) {
912                 return tevent_req_post(req, ev);
913         }
914         tevent_req_set_callback(subreq, cli_mkdir_done, req);
915         return req;
916 }
917
918 static void cli_mkdir_done(struct tevent_req *subreq)
919 {
920         struct tevent_req *req = tevent_req_callback_data(
921                 subreq, struct tevent_req);
922         NTSTATUS status;
923
924         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
925         TALLOC_FREE(subreq);
926         if (!NT_STATUS_IS_OK(status)) {
927                 tevent_req_nterror(req, status);
928                 return;
929         }
930         tevent_req_done(req);
931 }
932
933 NTSTATUS cli_mkdir_recv(struct tevent_req *req)
934 {
935         return tevent_req_simple_recv_ntstatus(req);
936 }
937
938 NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
939 {
940         TALLOC_CTX *frame = talloc_stackframe();
941         struct event_context *ev;
942         struct tevent_req *req;
943         NTSTATUS status = NT_STATUS_OK;
944
945         if (cli_has_async_calls(cli)) {
946                 /*
947                  * Can't use sync call while an async call is in flight
948                  */
949                 status = NT_STATUS_INVALID_PARAMETER;
950                 goto fail;
951         }
952
953         ev = event_context_init(frame);
954         if (ev == NULL) {
955                 status = NT_STATUS_NO_MEMORY;
956                 goto fail;
957         }
958
959         req = cli_mkdir_send(frame, ev, cli, dname);
960         if (req == NULL) {
961                 status = NT_STATUS_NO_MEMORY;
962                 goto fail;
963         }
964
965         if (!tevent_req_poll(req, ev)) {
966                 status = map_nt_error_from_unix(errno);
967                 goto fail;
968         }
969
970         status = cli_mkdir_recv(req);
971
972  fail:
973         TALLOC_FREE(frame);
974         if (!NT_STATUS_IS_OK(status)) {
975                 cli_set_error(cli, status);
976         }
977         return status;
978 }
979
980 /****************************************************************************
981  Remove a directory.
982 ****************************************************************************/
983
984 static void cli_rmdir_done(struct tevent_req *subreq);
985
986 struct cli_rmdir_state {
987         int dummy;
988 };
989
990 struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
991                                   struct event_context *ev,
992                                   struct cli_state *cli,
993                                   const char *dname)
994 {
995         struct tevent_req *req = NULL, *subreq = NULL;
996         struct cli_rmdir_state *state = NULL;
997         uint8_t additional_flags = 0;
998         uint8_t *bytes = NULL;
999
1000         req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
1001         if (req == NULL) {
1002                 return NULL;
1003         }
1004
1005         bytes = talloc_array(state, uint8_t, 1);
1006         if (tevent_req_nomem(bytes, req)) {
1007                 return tevent_req_post(req, ev);
1008         }
1009         bytes[0] = 4;
1010         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), dname,
1011                                    strlen(dname)+1, NULL);
1012
1013         if (tevent_req_nomem(bytes, req)) {
1014                 return tevent_req_post(req, ev);
1015         }
1016
1017         subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
1018                               0, NULL, talloc_get_size(bytes), bytes);
1019         if (tevent_req_nomem(subreq, req)) {
1020                 return tevent_req_post(req, ev);
1021         }
1022         tevent_req_set_callback(subreq, cli_rmdir_done, req);
1023         return req;
1024 }
1025
1026 static void cli_rmdir_done(struct tevent_req *subreq)
1027 {
1028         struct tevent_req *req = tevent_req_callback_data(
1029                 subreq, struct tevent_req);
1030         NTSTATUS status;
1031
1032         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1033         TALLOC_FREE(subreq);
1034         if (!NT_STATUS_IS_OK(status)) {
1035                 tevent_req_nterror(req, status);
1036                 return;
1037         }
1038         tevent_req_done(req);
1039 }
1040
1041 NTSTATUS cli_rmdir_recv(struct tevent_req *req)
1042 {
1043         return tevent_req_simple_recv_ntstatus(req);
1044 }
1045
1046 NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
1047 {
1048         TALLOC_CTX *frame = talloc_stackframe();
1049         struct event_context *ev;
1050         struct tevent_req *req;
1051         NTSTATUS status = NT_STATUS_OK;
1052
1053         if (cli_has_async_calls(cli)) {
1054                 /*
1055                  * Can't use sync call while an async call is in flight
1056                  */
1057                 status = NT_STATUS_INVALID_PARAMETER;
1058                 goto fail;
1059         }
1060
1061         ev = event_context_init(frame);
1062         if (ev == NULL) {
1063                 status = NT_STATUS_NO_MEMORY;
1064                 goto fail;
1065         }
1066
1067         req = cli_rmdir_send(frame, ev, cli, dname);
1068         if (req == NULL) {
1069                 status = NT_STATUS_NO_MEMORY;
1070                 goto fail;
1071         }
1072
1073         if (!tevent_req_poll(req, ev)) {
1074                 status = map_nt_error_from_unix(errno);
1075                 goto fail;
1076         }
1077
1078         status = cli_rmdir_recv(req);
1079
1080  fail:
1081         TALLOC_FREE(frame);
1082         if (!NT_STATUS_IS_OK(status)) {
1083                 cli_set_error(cli, status);
1084         }
1085         return status;
1086 }
1087
1088 /****************************************************************************
1089  Set or clear the delete on close flag.
1090 ****************************************************************************/
1091
1092 int cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
1093 {
1094         unsigned int data_len = 1;
1095         unsigned int param_len = 6;
1096         uint16_t setup = TRANSACT2_SETFILEINFO;
1097         char param[6];
1098         unsigned char data;
1099         char *rparam=NULL, *rdata=NULL;
1100
1101         memset(param, 0, param_len);
1102         SSVAL(param,0,fnum);
1103         SSVAL(param,2,SMB_SET_FILE_DISPOSITION_INFO);
1104
1105         data = flag ? 1 : 0;
1106
1107         if (!cli_send_trans(cli, SMBtrans2,
1108                         NULL,                        /* name */
1109                         -1, 0,                          /* fid, flags */
1110                         &setup, 1, 0,                   /* setup, length, max */
1111                         param, param_len, 2,            /* param, length, max */
1112                         (char *)&data,  data_len, cli->max_xmit /* data, length, max */
1113                         )) {
1114                 return false;
1115         }
1116
1117         if (!cli_receive_trans(cli, SMBtrans2,
1118                         &rparam, &param_len,
1119                         &rdata, &data_len)) {
1120                 return false;
1121         }
1122
1123         SAFE_FREE(rdata);
1124         SAFE_FREE(rparam);
1125
1126         return true;
1127 }
1128
1129 struct cli_ntcreate_state {
1130         uint16_t vwv[24];
1131         uint16_t fnum;
1132 };
1133
1134 static void cli_ntcreate_done(struct tevent_req *subreq);
1135
1136 struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
1137                                      struct event_context *ev,
1138                                      struct cli_state *cli,
1139                                      const char *fname,
1140                                      uint32_t CreatFlags,
1141                                      uint32_t DesiredAccess,
1142                                      uint32_t FileAttributes,
1143                                      uint32_t ShareAccess,
1144                                      uint32_t CreateDisposition,
1145                                      uint32_t CreateOptions,
1146                                      uint8_t SecurityFlags)
1147 {
1148         struct tevent_req *req, *subreq;
1149         struct cli_ntcreate_state *state;
1150         uint16_t *vwv;
1151         uint8_t *bytes;
1152         size_t converted_len;
1153
1154         req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
1155         if (req == NULL) {
1156                 return NULL;
1157         }
1158         vwv = state->vwv;
1159
1160         SCVAL(vwv+0, 0, 0xFF);
1161         SCVAL(vwv+0, 1, 0);
1162         SSVAL(vwv+1, 0, 0);
1163         SCVAL(vwv+2, 0, 0);
1164
1165         if (cli->use_oplocks) {
1166                 CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
1167         }
1168         SIVAL(vwv+3, 1, CreatFlags);
1169         SIVAL(vwv+5, 1, 0x0);   /* RootDirectoryFid */
1170         SIVAL(vwv+7, 1, DesiredAccess);
1171         SIVAL(vwv+9, 1, 0x0);   /* AllocationSize */
1172         SIVAL(vwv+11, 1, 0x0);  /* AllocationSize */
1173         SIVAL(vwv+13, 1, FileAttributes);
1174         SIVAL(vwv+15, 1, ShareAccess);
1175         SIVAL(vwv+17, 1, CreateDisposition);
1176         SIVAL(vwv+19, 1, CreateOptions);
1177         SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */
1178         SCVAL(vwv+23, 1, SecurityFlags);
1179
1180         bytes = talloc_array(state, uint8_t, 0);
1181         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli),
1182                                    fname, strlen(fname)+1,
1183                                    &converted_len);
1184
1185         /* sigh. this copes with broken netapp filer behaviour */
1186         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL);
1187
1188         if (tevent_req_nomem(bytes, req)) {
1189                 return tevent_req_post(req, ev);
1190         }
1191
1192         SIVAL(vwv+2, 1, converted_len);
1193
1194         subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv,
1195                               talloc_get_size(bytes), bytes);
1196         if (tevent_req_nomem(subreq, req)) {
1197                 return tevent_req_post(req, ev);
1198         }
1199         tevent_req_set_callback(subreq, cli_ntcreate_done, req);
1200         return req;
1201 }
1202
1203 static void cli_ntcreate_done(struct tevent_req *subreq)
1204 {
1205         struct tevent_req *req = tevent_req_callback_data(
1206                 subreq, struct tevent_req);
1207         struct cli_ntcreate_state *state = tevent_req_data(
1208                 req, struct cli_ntcreate_state);
1209         uint8_t wct;
1210         uint16_t *vwv;
1211         uint32_t num_bytes;
1212         uint8_t *bytes;
1213         NTSTATUS status;
1214
1215         status = cli_smb_recv(subreq, 3, &wct, &vwv, &num_bytes, &bytes);
1216         if (!NT_STATUS_IS_OK(status)) {
1217                 TALLOC_FREE(subreq);
1218                 tevent_req_nterror(req, status);
1219                 return;
1220         }
1221         state->fnum = SVAL(vwv+2, 1);
1222         tevent_req_done(req);
1223 }
1224
1225 NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum)
1226 {
1227         struct cli_ntcreate_state *state = tevent_req_data(
1228                 req, struct cli_ntcreate_state);
1229         NTSTATUS status;
1230
1231         if (tevent_req_is_nterror(req, &status)) {
1232                 return status;
1233         }
1234         *pfnum = state->fnum;
1235         return NT_STATUS_OK;
1236 }
1237
1238 NTSTATUS cli_ntcreate(struct cli_state *cli,
1239                       const char *fname,
1240                       uint32_t CreatFlags,
1241                       uint32_t DesiredAccess,
1242                       uint32_t FileAttributes,
1243                       uint32_t ShareAccess,
1244                       uint32_t CreateDisposition,
1245                       uint32_t CreateOptions,
1246                       uint8_t SecurityFlags,
1247                       uint16_t *pfid)
1248 {
1249         TALLOC_CTX *frame = talloc_stackframe();
1250         struct event_context *ev;
1251         struct tevent_req *req;
1252         NTSTATUS status = NT_STATUS_OK;
1253
1254         if (cli_has_async_calls(cli)) {
1255                 /*
1256                  * Can't use sync call while an async call is in flight
1257                  */
1258                 status = NT_STATUS_INVALID_PARAMETER;
1259                 goto fail;
1260         }
1261
1262         ev = event_context_init(frame);
1263         if (ev == NULL) {
1264                 status = NT_STATUS_NO_MEMORY;
1265                 goto fail;
1266         }
1267
1268         req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
1269                                 DesiredAccess, FileAttributes, ShareAccess,
1270                                 CreateDisposition, CreateOptions,
1271                                 SecurityFlags);
1272         if (req == NULL) {
1273                 status = NT_STATUS_NO_MEMORY;
1274                 goto fail;
1275         }
1276
1277         if (!tevent_req_poll(req, ev)) {
1278                 status = map_nt_error_from_unix(errno);
1279                 goto fail;
1280         }
1281
1282         status = cli_ntcreate_recv(req, pfid);
1283  fail:
1284         TALLOC_FREE(frame);
1285         if (!NT_STATUS_IS_OK(status)) {
1286                 cli_set_error(cli, status);
1287         }
1288         return status;
1289 }
1290
1291 /***********************************************************
1292  Common function for pushing stings, used by smb_bytes_push_str()
1293  and trans_bytes_push_str(). Only difference is the align_odd
1294  parameter setting.
1295 ***********************************************************/
1296
1297 static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
1298                                 const char *str, size_t str_len,
1299                                 bool align_odd,
1300                                 size_t *pconverted_size)
1301 {
1302         size_t buflen;
1303         char *converted;
1304         size_t converted_size;
1305
1306         if (buf == NULL) {
1307                 return NULL;
1308         }
1309
1310         buflen = talloc_get_size(buf);
1311
1312         if (align_odd && ucs2 && (buflen % 2 == 0)) {
1313                 /*
1314                  * We're pushing into an SMB buffer, align odd
1315                  */
1316                 buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t, buflen + 1);
1317                 if (buf == NULL) {
1318                         return NULL;
1319                 }
1320                 buf[buflen] = '\0';
1321                 buflen += 1;
1322         }
1323
1324         if (!convert_string_talloc(talloc_tos(), CH_UNIX,
1325                                    ucs2 ? CH_UTF16LE : CH_DOS,
1326                                    str, str_len, &converted,
1327                                    &converted_size, true)) {
1328                 return NULL;
1329         }
1330
1331         buf = TALLOC_REALLOC_ARRAY(NULL, buf, uint8_t,
1332                                    buflen + converted_size);
1333         if (buf == NULL) {
1334                 TALLOC_FREE(converted);
1335                 return NULL;
1336         }
1337
1338         memcpy(buf + buflen, converted, converted_size);
1339
1340         TALLOC_FREE(converted);
1341
1342         if (pconverted_size) {
1343                 *pconverted_size = converted_size;
1344         }
1345
1346         return buf;
1347 }
1348
1349 /***********************************************************
1350  Push a string into an SMB buffer, with odd byte alignment
1351  if it's a UCS2 string.
1352 ***********************************************************/
1353
1354 uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
1355                             const char *str, size_t str_len,
1356                             size_t *pconverted_size)
1357 {
1358         return internal_bytes_push_str(buf, ucs2, str, str_len,
1359                         true, pconverted_size);
1360 }
1361
1362 /***********************************************************
1363  Same as smb_bytes_push_str(), but without the odd byte
1364  align for ucs2 (we're pushing into a param or data block).
1365  static for now, although this will probably change when
1366  other modules use async trans calls.
1367 ***********************************************************/
1368
1369 static uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
1370                             const char *str, size_t str_len,
1371                             size_t *pconverted_size)
1372 {
1373         return internal_bytes_push_str(buf, ucs2, str, str_len,
1374                         false, pconverted_size);
1375 }
1376
1377 /****************************************************************************
1378  Open a file
1379  WARNING: if you open with O_WRONLY then getattrE won't work!
1380 ****************************************************************************/
1381
1382 struct cli_open_state {
1383         uint16_t vwv[15];
1384         uint16_t fnum;
1385         struct iovec bytes;
1386 };
1387
1388 static void cli_open_done(struct tevent_req *subreq);
1389
1390 struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx,
1391                                    struct event_context *ev,
1392                                    struct cli_state *cli, const char *fname,
1393                                    int flags, int share_mode,
1394                                    struct tevent_req **psmbreq)
1395 {
1396         struct tevent_req *req, *subreq;
1397         struct cli_open_state *state;
1398         unsigned openfn;
1399         unsigned accessmode;
1400         uint8_t additional_flags;
1401         uint8_t *bytes;
1402
1403         req = tevent_req_create(mem_ctx, &state, struct cli_open_state);
1404         if (req == NULL) {
1405                 return NULL;
1406         }
1407
1408         openfn = 0;
1409         if (flags & O_CREAT) {
1410                 openfn |= (1<<4);
1411         }
1412         if (!(flags & O_EXCL)) {
1413                 if (flags & O_TRUNC)
1414                         openfn |= (1<<1);
1415                 else
1416                         openfn |= (1<<0);
1417         }
1418
1419         accessmode = (share_mode<<4);
1420
1421         if ((flags & O_ACCMODE) == O_RDWR) {
1422                 accessmode |= 2;
1423         } else if ((flags & O_ACCMODE) == O_WRONLY) {
1424                 accessmode |= 1;
1425         }
1426
1427 #if defined(O_SYNC)
1428         if ((flags & O_SYNC) == O_SYNC) {
1429                 accessmode |= (1<<14);
1430         }
1431 #endif /* O_SYNC */
1432
1433         if (share_mode == DENY_FCB) {
1434                 accessmode = 0xFF;
1435         }
1436
1437         SCVAL(state->vwv + 0, 0, 0xFF);
1438         SCVAL(state->vwv + 0, 1, 0);
1439         SSVAL(state->vwv + 1, 0, 0);
1440         SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
1441         SSVAL(state->vwv + 3, 0, accessmode);
1442         SSVAL(state->vwv + 4, 0, aSYSTEM | aHIDDEN);
1443         SSVAL(state->vwv + 5, 0, 0);
1444         SIVAL(state->vwv + 6, 0, 0);
1445         SSVAL(state->vwv + 8, 0, openfn);
1446         SIVAL(state->vwv + 9, 0, 0);
1447         SIVAL(state->vwv + 11, 0, 0);
1448         SIVAL(state->vwv + 13, 0, 0);
1449
1450         additional_flags = 0;
1451
1452         if (cli->use_oplocks) {
1453                 /* if using oplocks then ask for a batch oplock via
1454                    core and extended methods */
1455                 additional_flags =
1456                         FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
1457                 SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
1458         }
1459
1460         bytes = talloc_array(state, uint8_t, 0);
1461         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
1462                                    strlen(fname)+1, NULL);
1463
1464         if (tevent_req_nomem(bytes, req)) {
1465                 return tevent_req_post(req, ev);
1466         }
1467
1468         state->bytes.iov_base = bytes;
1469         state->bytes.iov_len = talloc_get_size(bytes);
1470
1471         subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
1472                                     15, state->vwv, 1, &state->bytes);
1473         if (subreq == NULL) {
1474                 TALLOC_FREE(req);
1475                 return NULL;
1476         }
1477         tevent_req_set_callback(subreq, cli_open_done, req);
1478         *psmbreq = subreq;
1479         return req;
1480 }
1481
1482 struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
1483                                  struct cli_state *cli, const char *fname,
1484                                  int flags, int share_mode)
1485 {
1486         struct tevent_req *req, *subreq;
1487
1488         req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode,
1489                               &subreq);
1490         if ((req == NULL) || !cli_smb_req_send(subreq)) {
1491                 TALLOC_FREE(req);
1492                 return NULL;
1493         }
1494         return req;
1495 }
1496
1497 static void cli_open_done(struct tevent_req *subreq)
1498 {
1499         struct tevent_req *req = tevent_req_callback_data(
1500                 subreq, struct tevent_req);
1501         struct cli_open_state *state = tevent_req_data(
1502                 req, struct cli_open_state);
1503         uint8_t wct;
1504         uint16_t *vwv;
1505         NTSTATUS status;
1506
1507         status = cli_smb_recv(subreq, 3, &wct, &vwv, NULL, NULL);
1508         if (!NT_STATUS_IS_OK(status)) {
1509                 TALLOC_FREE(subreq);
1510                 tevent_req_nterror(req, status);
1511                 return;
1512         }
1513         state->fnum = SVAL(vwv+2, 0);
1514         tevent_req_done(req);
1515 }
1516
1517 NTSTATUS cli_open_recv(struct tevent_req *req, uint16_t *pfnum)
1518 {
1519         struct cli_open_state *state = tevent_req_data(
1520                 req, struct cli_open_state);
1521         NTSTATUS status;
1522
1523         if (tevent_req_is_nterror(req, &status)) {
1524                 return status;
1525         }
1526         *pfnum = state->fnum;
1527         return NT_STATUS_OK;
1528 }
1529
1530 NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
1531              int share_mode, uint16_t *pfnum)
1532 {
1533         TALLOC_CTX *frame = talloc_stackframe();
1534         struct event_context *ev;
1535         struct tevent_req *req;
1536         NTSTATUS status = NT_STATUS_OK;
1537
1538         if (cli_has_async_calls(cli)) {
1539                 /*
1540                  * Can't use sync call while an async call is in flight
1541                  */
1542                 status = NT_STATUS_INVALID_PARAMETER;
1543                 goto fail;
1544         }
1545
1546         ev = event_context_init(frame);
1547         if (ev == NULL) {
1548                 status = NT_STATUS_NO_MEMORY;
1549                 goto fail;
1550         }
1551
1552         req = cli_open_send(frame, ev, cli, fname, flags, share_mode);
1553         if (req == NULL) {
1554                 status = NT_STATUS_NO_MEMORY;
1555                 goto fail;
1556         }
1557
1558         if (!tevent_req_poll(req, ev)) {
1559                 status = map_nt_error_from_unix(errno);
1560                 goto fail;
1561         }
1562
1563         status = cli_open_recv(req, pfnum);
1564  fail:
1565         TALLOC_FREE(frame);
1566         if (!NT_STATUS_IS_OK(status)) {
1567                 cli_set_error(cli, status);
1568         }
1569         return status;
1570 }
1571
1572 /****************************************************************************
1573  Close a file.
1574 ****************************************************************************/
1575
1576 struct cli_close_state {
1577         uint16_t vwv[3];
1578 };
1579
1580 static void cli_close_done(struct tevent_req *subreq);
1581
1582 struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
1583                                 struct event_context *ev,
1584                                 struct cli_state *cli,
1585                                 uint16_t fnum,
1586                                 struct tevent_req **psubreq)
1587 {
1588         struct tevent_req *req, *subreq;
1589         struct cli_close_state *state;
1590
1591         req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
1592         if (req == NULL) {
1593                 return NULL;
1594         }
1595         SSVAL(state->vwv+0, 0, fnum);
1596         SIVALS(state->vwv+1, 0, -1);
1597
1598         subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv,
1599                                     0, NULL);
1600         if (subreq == NULL) {
1601                 TALLOC_FREE(req);
1602                 return NULL;
1603         }
1604         tevent_req_set_callback(subreq, cli_close_done, req);
1605         *psubreq = subreq;
1606         return req;
1607 }
1608
1609 struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
1610                                 struct event_context *ev,
1611                                 struct cli_state *cli,
1612                                 uint16_t fnum)
1613 {
1614         struct tevent_req *req, *subreq;
1615
1616         req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
1617         if ((req == NULL) || !cli_smb_req_send(subreq)) {
1618                 TALLOC_FREE(req);
1619                 return NULL;
1620         }
1621         return req;
1622 }
1623
1624 static void cli_close_done(struct tevent_req *subreq)
1625 {
1626         struct tevent_req *req = tevent_req_callback_data(
1627                 subreq, struct tevent_req);
1628         NTSTATUS status;
1629
1630         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
1631         TALLOC_FREE(subreq);
1632         if (!NT_STATUS_IS_OK(status)) {
1633                 tevent_req_nterror(req, status);
1634                 return;
1635         }
1636         tevent_req_done(req);
1637 }
1638
1639 NTSTATUS cli_close_recv(struct tevent_req *req)
1640 {
1641         return tevent_req_simple_recv_ntstatus(req);
1642 }
1643
1644 NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
1645 {
1646         TALLOC_CTX *frame = talloc_stackframe();
1647         struct event_context *ev;
1648         struct tevent_req *req;
1649         NTSTATUS status = NT_STATUS_OK;
1650
1651         if (cli_has_async_calls(cli)) {
1652                 /*
1653                  * Can't use sync call while an async call is in flight
1654                  */
1655                 status = NT_STATUS_INVALID_PARAMETER;
1656                 goto fail;
1657         }
1658
1659         ev = event_context_init(frame);
1660         if (ev == NULL) {
1661                 status = NT_STATUS_NO_MEMORY;
1662                 goto fail;
1663         }
1664
1665         req = cli_close_send(frame, ev, cli, fnum);
1666         if (req == NULL) {
1667                 status = NT_STATUS_NO_MEMORY;
1668                 goto fail;
1669         }
1670
1671         if (!tevent_req_poll(req, ev)) {
1672                 status = map_nt_error_from_unix(errno);
1673                 goto fail;
1674         }
1675
1676         status = cli_close_recv(req);
1677  fail:
1678         TALLOC_FREE(frame);
1679         if (!NT_STATUS_IS_OK(status)) {
1680                 cli_set_error(cli, status);
1681         }
1682         return status;
1683 }
1684
1685 /****************************************************************************
1686  Truncate a file to a specified size
1687 ****************************************************************************/
1688
1689 bool cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
1690 {
1691         unsigned int param_len = 6;
1692         unsigned int data_len = 8;
1693         uint16_t setup = TRANSACT2_SETFILEINFO;
1694         char param[6];
1695         unsigned char data[8];
1696         char *rparam=NULL, *rdata=NULL;
1697         int saved_timeout = cli->timeout;
1698
1699         SSVAL(param,0,fnum);
1700         SSVAL(param,2,SMB_SET_FILE_END_OF_FILE_INFO);
1701         SSVAL(param,4,0);
1702
1703         SBVAL(data, 0, size);
1704
1705         if (!cli_send_trans(cli, SMBtrans2,
1706                             NULL,                    /* name */
1707                             -1, 0,                   /* fid, flags */
1708                             &setup, 1, 0,            /* setup, length, max */
1709                             param, param_len, 2,     /* param, length, max */
1710                             (char *)&data,  data_len,/* data, length, ... */
1711                             cli->max_xmit)) {        /* ... max */
1712                 cli->timeout = saved_timeout;
1713                 return False;
1714         }
1715
1716         if (!cli_receive_trans(cli, SMBtrans2,
1717                                 &rparam, &param_len,
1718                                 &rdata, &data_len)) {
1719                 cli->timeout = saved_timeout;
1720                 SAFE_FREE(rdata);
1721                 SAFE_FREE(rparam);
1722                 return False;
1723         }
1724
1725         cli->timeout = saved_timeout;
1726
1727         SAFE_FREE(rdata);
1728         SAFE_FREE(rparam);
1729
1730         return True;
1731 }
1732
1733
1734 /****************************************************************************
1735  send a lock with a specified locktype
1736  this is used for testing LOCKING_ANDX_CANCEL_LOCK
1737 ****************************************************************************/
1738
1739 NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
1740                       uint32_t offset, uint32_t len,
1741                       int timeout, unsigned char locktype)
1742 {
1743         char *p;
1744         int saved_timeout = cli->timeout;
1745
1746         memset(cli->outbuf,'\0',smb_size);
1747         memset(cli->inbuf,'\0', smb_size);
1748
1749         cli_set_message(cli->outbuf,8,0,True);
1750
1751         SCVAL(cli->outbuf,smb_com,SMBlockingX);
1752         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1753         cli_setup_packet(cli);
1754
1755         SCVAL(cli->outbuf,smb_vwv0,0xFF);
1756         SSVAL(cli->outbuf,smb_vwv2,fnum);
1757         SCVAL(cli->outbuf,smb_vwv3,locktype);
1758         SIVALS(cli->outbuf, smb_vwv4, timeout);
1759         SSVAL(cli->outbuf,smb_vwv6,0);
1760         SSVAL(cli->outbuf,smb_vwv7,1);
1761
1762         p = smb_buf(cli->outbuf);
1763         SSVAL(p, 0, cli->pid);
1764         SIVAL(p, 2, offset);
1765         SIVAL(p, 6, len);
1766
1767         p += 10;
1768
1769         cli_setup_bcc(cli, p);
1770
1771         cli_send_smb(cli);
1772
1773         if (timeout != 0) {
1774                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
1775         }
1776
1777         if (!cli_receive_smb(cli)) {
1778                 cli->timeout = saved_timeout;
1779                 return NT_STATUS_UNSUCCESSFUL;
1780         }
1781
1782         cli->timeout = saved_timeout;
1783
1784         return cli_nt_error(cli);
1785 }
1786
1787 /****************************************************************************
1788  Lock a file.
1789  note that timeout is in units of 2 milliseconds
1790 ****************************************************************************/
1791
1792 bool cli_lock(struct cli_state *cli, uint16_t fnum,
1793               uint32_t offset, uint32_t len, int timeout, enum brl_type lock_type)
1794 {
1795         char *p;
1796         int saved_timeout = cli->timeout;
1797
1798         memset(cli->outbuf,'\0',smb_size);
1799         memset(cli->inbuf,'\0', smb_size);
1800
1801         cli_set_message(cli->outbuf,8,0,True);
1802
1803         SCVAL(cli->outbuf,smb_com,SMBlockingX);
1804         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1805         cli_setup_packet(cli);
1806
1807         SCVAL(cli->outbuf,smb_vwv0,0xFF);
1808         SSVAL(cli->outbuf,smb_vwv2,fnum);
1809         SCVAL(cli->outbuf,smb_vwv3,(lock_type == READ_LOCK? 1 : 0));
1810         SIVALS(cli->outbuf, smb_vwv4, timeout);
1811         SSVAL(cli->outbuf,smb_vwv6,0);
1812         SSVAL(cli->outbuf,smb_vwv7,1);
1813
1814         p = smb_buf(cli->outbuf);
1815         SSVAL(p, 0, cli->pid);
1816         SIVAL(p, 2, offset);
1817         SIVAL(p, 6, len);
1818
1819         p += 10;
1820
1821         cli_setup_bcc(cli, p);
1822
1823         cli_send_smb(cli);
1824
1825         if (timeout != 0) {
1826                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout*2 + 5*1000);
1827         }
1828
1829         if (!cli_receive_smb(cli)) {
1830                 cli->timeout = saved_timeout;
1831                 return False;
1832         }
1833
1834         cli->timeout = saved_timeout;
1835
1836         if (cli_is_error(cli)) {
1837                 return False;
1838         }
1839
1840         return True;
1841 }
1842
1843 /****************************************************************************
1844  Unlock a file.
1845 ****************************************************************************/
1846
1847 bool cli_unlock(struct cli_state *cli, uint16_t fnum, uint32_t offset, uint32_t len)
1848 {
1849         char *p;
1850
1851         memset(cli->outbuf,'\0',smb_size);
1852         memset(cli->inbuf,'\0',smb_size);
1853
1854         cli_set_message(cli->outbuf,8,0,True);
1855
1856         SCVAL(cli->outbuf,smb_com,SMBlockingX);
1857         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1858         cli_setup_packet(cli);
1859
1860         SCVAL(cli->outbuf,smb_vwv0,0xFF);
1861         SSVAL(cli->outbuf,smb_vwv2,fnum);
1862         SCVAL(cli->outbuf,smb_vwv3,0);
1863         SIVALS(cli->outbuf, smb_vwv4, 0);
1864         SSVAL(cli->outbuf,smb_vwv6,1);
1865         SSVAL(cli->outbuf,smb_vwv7,0);
1866
1867         p = smb_buf(cli->outbuf);
1868         SSVAL(p, 0, cli->pid);
1869         SIVAL(p, 2, offset);
1870         SIVAL(p, 6, len);
1871         p += 10;
1872         cli_setup_bcc(cli, p);
1873         cli_send_smb(cli);
1874         if (!cli_receive_smb(cli)) {
1875                 return False;
1876         }
1877
1878         if (cli_is_error(cli)) {
1879                 return False;
1880         }
1881
1882         return True;
1883 }
1884
1885 /****************************************************************************
1886  Lock a file with 64 bit offsets.
1887 ****************************************************************************/
1888
1889 bool cli_lock64(struct cli_state *cli, uint16_t fnum,
1890                 uint64_t offset, uint64_t len, int timeout, enum brl_type lock_type)
1891 {
1892         char *p;
1893         int saved_timeout = cli->timeout;
1894         int ltype;
1895
1896         if (! (cli->capabilities & CAP_LARGE_FILES)) {
1897                 return cli_lock(cli, fnum, offset, len, timeout, lock_type);
1898         }
1899
1900         ltype = (lock_type == READ_LOCK? 1 : 0);
1901         ltype |= LOCKING_ANDX_LARGE_FILES;
1902
1903         memset(cli->outbuf,'\0',smb_size);
1904         memset(cli->inbuf,'\0', smb_size);
1905
1906         cli_set_message(cli->outbuf,8,0,True);
1907
1908         SCVAL(cli->outbuf,smb_com,SMBlockingX);
1909         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1910         cli_setup_packet(cli);
1911
1912         SCVAL(cli->outbuf,smb_vwv0,0xFF);
1913         SSVAL(cli->outbuf,smb_vwv2,fnum);
1914         SCVAL(cli->outbuf,smb_vwv3,ltype);
1915         SIVALS(cli->outbuf, smb_vwv4, timeout);
1916         SSVAL(cli->outbuf,smb_vwv6,0);
1917         SSVAL(cli->outbuf,smb_vwv7,1);
1918
1919         p = smb_buf(cli->outbuf);
1920         SIVAL(p, 0, cli->pid);
1921         SOFF_T_R(p, 4, offset);
1922         SOFF_T_R(p, 12, len);
1923         p += 20;
1924
1925         cli_setup_bcc(cli, p);
1926         cli_send_smb(cli);
1927
1928         if (timeout != 0) {
1929                 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 5*1000);
1930         }
1931
1932         if (!cli_receive_smb(cli)) {
1933                 cli->timeout = saved_timeout;
1934                 return False;
1935         }
1936
1937         cli->timeout = saved_timeout;
1938
1939         if (cli_is_error(cli)) {
1940                 return False;
1941         }
1942
1943         return True;
1944 }
1945
1946 /****************************************************************************
1947  Unlock a file with 64 bit offsets.
1948 ****************************************************************************/
1949
1950 bool cli_unlock64(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
1951 {
1952         char *p;
1953
1954         if (! (cli->capabilities & CAP_LARGE_FILES)) {
1955                 return cli_unlock(cli, fnum, offset, len);
1956         }
1957
1958         memset(cli->outbuf,'\0',smb_size);
1959         memset(cli->inbuf,'\0',smb_size);
1960
1961         cli_set_message(cli->outbuf,8,0,True);
1962
1963         SCVAL(cli->outbuf,smb_com,SMBlockingX);
1964         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1965         cli_setup_packet(cli);
1966
1967         SCVAL(cli->outbuf,smb_vwv0,0xFF);
1968         SSVAL(cli->outbuf,smb_vwv2,fnum);
1969         SCVAL(cli->outbuf,smb_vwv3,LOCKING_ANDX_LARGE_FILES);
1970         SIVALS(cli->outbuf, smb_vwv4, 0);
1971         SSVAL(cli->outbuf,smb_vwv6,1);
1972         SSVAL(cli->outbuf,smb_vwv7,0);
1973
1974         p = smb_buf(cli->outbuf);
1975         SIVAL(p, 0, cli->pid);
1976         SOFF_T_R(p, 4, offset);
1977         SOFF_T_R(p, 12, len);
1978         p += 20;
1979         cli_setup_bcc(cli, p);
1980         cli_send_smb(cli);
1981         if (!cli_receive_smb(cli)) {
1982                 return False;
1983         }
1984
1985         if (cli_is_error(cli)) {
1986                 return False;
1987         }
1988
1989         return True;
1990 }
1991
1992 /****************************************************************************
1993  Get/unlock a POSIX lock on a file - internal function.
1994 ****************************************************************************/
1995
1996 static bool cli_posix_lock_internal(struct cli_state *cli, uint16_t fnum,
1997                 uint64_t offset, uint64_t len, bool wait_lock, enum brl_type lock_type)
1998 {
1999         unsigned int param_len = 4;
2000         unsigned int data_len = POSIX_LOCK_DATA_SIZE;
2001         uint16_t setup = TRANSACT2_SETFILEINFO;
2002         char param[4];
2003         unsigned char data[POSIX_LOCK_DATA_SIZE];
2004         char *rparam=NULL, *rdata=NULL;
2005         int saved_timeout = cli->timeout;
2006
2007         SSVAL(param,0,fnum);
2008         SSVAL(param,2,SMB_SET_POSIX_LOCK);
2009
2010         switch (lock_type) {
2011                 case READ_LOCK:
2012                         SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_READ);
2013                         break;
2014                 case WRITE_LOCK:
2015                         SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_WRITE);
2016                         break;
2017                 case UNLOCK_LOCK:
2018                         SSVAL(data, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
2019                         break;
2020                 default:
2021                         return False;
2022         }
2023
2024         if (wait_lock) {
2025                 SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_WAIT);
2026                 cli->timeout = 0x7FFFFFFF;
2027         } else {
2028                 SSVAL(data, POSIX_LOCK_FLAGS_OFFSET, POSIX_LOCK_FLAG_NOWAIT);
2029         }
2030
2031         SIVAL(data, POSIX_LOCK_PID_OFFSET, cli->pid);
2032         SOFF_T(data, POSIX_LOCK_START_OFFSET, offset);
2033         SOFF_T(data, POSIX_LOCK_LEN_OFFSET, len);
2034
2035         if (!cli_send_trans(cli, SMBtrans2,
2036                         NULL,                        /* name */
2037                         -1, 0,                          /* fid, flags */
2038                         &setup, 1, 0,                   /* setup, length, max */
2039                         param, param_len, 2,            /* param, length, max */
2040                         (char *)&data,  data_len, cli->max_xmit /* data, length, max */
2041                         )) {
2042                 cli->timeout = saved_timeout;
2043                 return False;
2044         }
2045
2046         if (!cli_receive_trans(cli, SMBtrans2,
2047                                 &rparam, &param_len,
2048                                 &rdata, &data_len)) {
2049                 cli->timeout = saved_timeout;
2050                 SAFE_FREE(rdata);
2051                 SAFE_FREE(rparam);
2052                 return False;
2053         }
2054
2055         cli->timeout = saved_timeout;
2056
2057         SAFE_FREE(rdata);
2058         SAFE_FREE(rparam);
2059
2060         return True;
2061 }
2062
2063 /****************************************************************************
2064  POSIX Lock a file.
2065 ****************************************************************************/
2066
2067 bool cli_posix_lock(struct cli_state *cli, uint16_t fnum,
2068                         uint64_t offset, uint64_t len,
2069                         bool wait_lock, enum brl_type lock_type)
2070 {
2071         if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
2072                 return False;
2073         }
2074         return cli_posix_lock_internal(cli, fnum, offset, len, wait_lock, lock_type);
2075 }
2076
2077 /****************************************************************************
2078  POSIX Unlock a file.
2079 ****************************************************************************/
2080
2081 bool cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
2082 {
2083         return cli_posix_lock_internal(cli, fnum, offset, len, False, UNLOCK_LOCK);
2084 }
2085
2086 /****************************************************************************
2087  POSIX Get any lock covering a file.
2088 ****************************************************************************/
2089
2090 bool cli_posix_getlock(struct cli_state *cli, uint16_t fnum, uint64_t *poffset, uint64_t *plen)
2091 {
2092         return True;
2093 }
2094
2095 /****************************************************************************
2096  Do a SMBgetattrE call.
2097 ****************************************************************************/
2098
2099 static void cli_getattrE_done(struct tevent_req *subreq);
2100
2101 struct cli_getattrE_state {
2102         uint16_t vwv[1];
2103         int zone_offset;
2104         uint16_t attr;
2105         SMB_OFF_T size;
2106         time_t change_time;
2107         time_t access_time;
2108         time_t write_time;
2109 };
2110
2111 struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
2112                                 struct event_context *ev,
2113                                 struct cli_state *cli,
2114                                 uint16_t fnum)
2115 {
2116         struct tevent_req *req = NULL, *subreq = NULL;
2117         struct cli_getattrE_state *state = NULL;
2118         uint8_t additional_flags = 0;
2119
2120         req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
2121         if (req == NULL) {
2122                 return NULL;
2123         }
2124
2125         state->zone_offset = cli->serverzone;
2126         SSVAL(state->vwv+0,0,fnum);
2127
2128         subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags,
2129                               1, state->vwv, 0, NULL);
2130         if (tevent_req_nomem(subreq, req)) {
2131                 return tevent_req_post(req, ev);
2132         }
2133         tevent_req_set_callback(subreq, cli_getattrE_done, req);
2134         return req;
2135 }
2136
2137 static void cli_getattrE_done(struct tevent_req *subreq)
2138 {
2139         struct tevent_req *req = tevent_req_callback_data(
2140                 subreq, struct tevent_req);
2141         struct cli_getattrE_state *state = tevent_req_data(
2142                 req, struct cli_getattrE_state);
2143         uint8_t wct;
2144         uint16_t *vwv = NULL;
2145         NTSTATUS status;
2146
2147         status = cli_smb_recv(subreq, 11, &wct, &vwv, NULL, NULL);
2148         if (!NT_STATUS_IS_OK(status)) {
2149                 tevent_req_nterror(req, status);
2150                 return;
2151         }
2152
2153         state->size = (SMB_OFF_T)IVAL(vwv+6,0);
2154         state->attr = SVAL(vwv+10,0);
2155         state->change_time = make_unix_date2(vwv+0, state->zone_offset);
2156         state->access_time = make_unix_date2(vwv+2, state->zone_offset);
2157         state->write_time = make_unix_date2(vwv+4, state->zone_offset);
2158
2159         TALLOC_FREE(subreq);
2160         tevent_req_done(req);
2161 }
2162
2163 NTSTATUS cli_getattrE_recv(struct tevent_req *req,
2164                         uint16_t *attr,
2165                         SMB_OFF_T *size,
2166                         time_t *change_time,
2167                         time_t *access_time,
2168                         time_t *write_time)
2169 {
2170         struct cli_getattrE_state *state = tevent_req_data(
2171                                 req, struct cli_getattrE_state);
2172         NTSTATUS status;
2173
2174         if (tevent_req_is_nterror(req, &status)) {
2175                 return status;
2176         }
2177         if (attr) {
2178                 *attr = state->attr;
2179         }
2180         if (size) {
2181                 *size = state->size;
2182         }
2183         if (change_time) {
2184                 *change_time = state->change_time;
2185         }
2186         if (access_time) {
2187                 *access_time = state->access_time;
2188         }
2189         if (write_time) {
2190                 *write_time = state->write_time;
2191         }
2192         return NT_STATUS_OK;
2193 }
2194
2195 NTSTATUS cli_getattrE(struct cli_state *cli,
2196                         uint16_t fnum,
2197                         uint16_t *attr,
2198                         SMB_OFF_T *size,
2199                         time_t *change_time,
2200                         time_t *access_time,
2201                         time_t *write_time)
2202 {
2203         TALLOC_CTX *frame = talloc_stackframe();
2204         struct event_context *ev = NULL;
2205         struct tevent_req *req = NULL;
2206         NTSTATUS status = NT_STATUS_OK;
2207
2208         if (cli_has_async_calls(cli)) {
2209                 /*
2210                  * Can't use sync call while an async call is in flight
2211                  */
2212                 status = NT_STATUS_INVALID_PARAMETER;
2213                 goto fail;
2214         }
2215
2216         ev = event_context_init(frame);
2217         if (ev == NULL) {
2218                 status = NT_STATUS_NO_MEMORY;
2219                 goto fail;
2220         }
2221
2222         req = cli_getattrE_send(frame, ev, cli, fnum);
2223         if (req == NULL) {
2224                 status = NT_STATUS_NO_MEMORY;
2225                 goto fail;
2226         }
2227
2228         if (!tevent_req_poll(req, ev)) {
2229                 status = map_nt_error_from_unix(errno);
2230                 goto fail;
2231         }
2232
2233         status = cli_getattrE_recv(req,
2234                                         attr,
2235                                         size,
2236                                         change_time,
2237                                         access_time,
2238                                         write_time);
2239
2240  fail:
2241         TALLOC_FREE(frame);
2242         if (!NT_STATUS_IS_OK(status)) {
2243                 cli_set_error(cli, status);
2244         }
2245         return status;
2246 }
2247
2248 /****************************************************************************
2249  Do a SMBgetatr call
2250 ****************************************************************************/
2251
2252 static void cli_getatr_done(struct tevent_req *subreq);
2253
2254 struct cli_getatr_state {
2255         int zone_offset;
2256         uint16_t attr;
2257         SMB_OFF_T size;
2258         time_t write_time;
2259 };
2260
2261 struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
2262                                 struct event_context *ev,
2263                                 struct cli_state *cli,
2264                                 const char *fname)
2265 {
2266         struct tevent_req *req = NULL, *subreq = NULL;
2267         struct cli_getatr_state *state = NULL;
2268         uint8_t additional_flags = 0;
2269         uint8_t *bytes = NULL;
2270
2271         req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
2272         if (req == NULL) {
2273                 return NULL;
2274         }
2275
2276         state->zone_offset = cli->serverzone;
2277
2278         bytes = talloc_array(state, uint8_t, 1);
2279         if (tevent_req_nomem(bytes, req)) {
2280                 return tevent_req_post(req, ev);
2281         }
2282         bytes[0] = 4;
2283         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
2284                                    strlen(fname)+1, NULL);
2285
2286         if (tevent_req_nomem(bytes, req)) {
2287                 return tevent_req_post(req, ev);
2288         }
2289
2290         subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
2291                               0, NULL, talloc_get_size(bytes), bytes);
2292         if (tevent_req_nomem(subreq, req)) {
2293                 return tevent_req_post(req, ev);
2294         }
2295         tevent_req_set_callback(subreq, cli_getatr_done, req);
2296         return req;
2297 }
2298
2299 static void cli_getatr_done(struct tevent_req *subreq)
2300 {
2301         struct tevent_req *req = tevent_req_callback_data(
2302                 subreq, struct tevent_req);
2303         struct cli_getatr_state *state = tevent_req_data(
2304                 req, struct cli_getatr_state);
2305         uint8_t wct;
2306         uint16_t *vwv = NULL;
2307         NTSTATUS status;
2308
2309         status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL);
2310         if (!NT_STATUS_IS_OK(status)) {
2311                 tevent_req_nterror(req, status);
2312                 return;
2313         }
2314
2315         state->attr = SVAL(vwv+0,0);
2316         state->size = (SMB_OFF_T)IVAL(vwv+3,0);
2317         state->write_time = make_unix_date3(vwv+1, state->zone_offset);
2318
2319         TALLOC_FREE(subreq);
2320         tevent_req_done(req);
2321 }
2322
2323 NTSTATUS cli_getatr_recv(struct tevent_req *req,
2324                         uint16_t *attr,
2325                         SMB_OFF_T *size,
2326                         time_t *write_time)
2327 {
2328         struct cli_getatr_state *state = tevent_req_data(
2329                                 req, struct cli_getatr_state);
2330         NTSTATUS status;
2331
2332         if (tevent_req_is_nterror(req, &status)) {
2333                 return status;
2334         }
2335         if (attr) {
2336                 *attr = state->attr;
2337         }
2338         if (size) {
2339                 *size = state->size;
2340         }
2341         if (write_time) {
2342                 *write_time = state->write_time;
2343         }
2344         return NT_STATUS_OK;
2345 }
2346
2347 NTSTATUS cli_getatr(struct cli_state *cli,
2348                         const char *fname,
2349                         uint16_t *attr,
2350                         SMB_OFF_T *size,
2351                         time_t *write_time)
2352 {
2353         TALLOC_CTX *frame = talloc_stackframe();
2354         struct event_context *ev = NULL;
2355         struct tevent_req *req = NULL;
2356         NTSTATUS status = NT_STATUS_OK;
2357
2358         if (cli_has_async_calls(cli)) {
2359                 /*
2360                  * Can't use sync call while an async call is in flight
2361                  */
2362                 status = NT_STATUS_INVALID_PARAMETER;
2363                 goto fail;
2364         }
2365
2366         ev = event_context_init(frame);
2367         if (ev == NULL) {
2368                 status = NT_STATUS_NO_MEMORY;
2369                 goto fail;
2370         }
2371
2372         req = cli_getatr_send(frame, ev, cli, fname);
2373         if (req == NULL) {
2374                 status = NT_STATUS_NO_MEMORY;
2375                 goto fail;
2376         }
2377
2378         if (!tevent_req_poll(req, ev)) {
2379                 status = map_nt_error_from_unix(errno);
2380                 goto fail;
2381         }
2382
2383         status = cli_getatr_recv(req,
2384                                 attr,
2385                                 size,
2386                                 write_time);
2387
2388  fail:
2389         TALLOC_FREE(frame);
2390         if (!NT_STATUS_IS_OK(status)) {
2391                 cli_set_error(cli, status);
2392         }
2393         return status;
2394 }
2395
2396 /****************************************************************************
2397  Do a SMBsetattrE call.
2398 ****************************************************************************/
2399
2400 static void cli_setattrE_done(struct tevent_req *subreq);
2401
2402 struct cli_setattrE_state {
2403         int dummy;
2404 };
2405
2406 struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
2407                                 struct event_context *ev,
2408                                 struct cli_state *cli,
2409                                 uint16_t fnum,
2410                                 time_t change_time,
2411                                 time_t access_time,
2412                                 time_t write_time)
2413 {
2414         struct tevent_req *req = NULL, *subreq = NULL;
2415         struct cli_setattrE_state *state = NULL;
2416         uint8_t additional_flags = 0;
2417         uint16_t vwv[7];
2418
2419         req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
2420         if (req == NULL) {
2421                 return NULL;
2422         }
2423
2424         memset(vwv, '\0', sizeof(vwv));
2425         SSVAL(vwv+0, 0, fnum);
2426         cli_put_dos_date2(cli, (char *)&vwv[1], 0, change_time);
2427         cli_put_dos_date2(cli, (char *)&vwv[3], 0, access_time);
2428         cli_put_dos_date2(cli, (char *)&vwv[5], 0, write_time);
2429
2430         subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags,
2431                               7, vwv, 0, NULL);
2432         if (tevent_req_nomem(subreq, req)) {
2433                 return tevent_req_post(req, ev);
2434         }
2435         tevent_req_set_callback(subreq, cli_setattrE_done, req);
2436         return req;
2437 }
2438
2439 static void cli_setattrE_done(struct tevent_req *subreq)
2440 {
2441         struct tevent_req *req = tevent_req_callback_data(
2442                 subreq, struct tevent_req);
2443         NTSTATUS status;
2444
2445         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2446         TALLOC_FREE(subreq);
2447         if (!NT_STATUS_IS_OK(status)) {
2448                 tevent_req_nterror(req, status);
2449                 return;
2450         }
2451         tevent_req_done(req);
2452 }
2453
2454 NTSTATUS cli_setattrE_recv(struct tevent_req *req)
2455 {
2456         return tevent_req_simple_recv_ntstatus(req);
2457 }
2458
2459 NTSTATUS cli_setattrE(struct cli_state *cli,
2460                         uint16_t fnum,
2461                         time_t change_time,
2462                         time_t access_time,
2463                         time_t write_time)
2464 {
2465         TALLOC_CTX *frame = talloc_stackframe();
2466         struct event_context *ev = NULL;
2467         struct tevent_req *req = NULL;
2468         NTSTATUS status = NT_STATUS_OK;
2469
2470         if (cli_has_async_calls(cli)) {
2471                 /*
2472                  * Can't use sync call while an async call is in flight
2473                  */
2474                 status = NT_STATUS_INVALID_PARAMETER;
2475                 goto fail;
2476         }
2477
2478         ev = event_context_init(frame);
2479         if (ev == NULL) {
2480                 status = NT_STATUS_NO_MEMORY;
2481                 goto fail;
2482         }
2483
2484         req = cli_setattrE_send(frame, ev,
2485                         cli,
2486                         fnum,
2487                         change_time,
2488                         access_time,
2489                         write_time);
2490
2491         if (req == NULL) {
2492                 status = NT_STATUS_NO_MEMORY;
2493                 goto fail;
2494         }
2495
2496         if (!tevent_req_poll(req, ev)) {
2497                 status = map_nt_error_from_unix(errno);
2498                 goto fail;
2499         }
2500
2501         status = cli_setattrE_recv(req);
2502
2503  fail:
2504         TALLOC_FREE(frame);
2505         if (!NT_STATUS_IS_OK(status)) {
2506                 cli_set_error(cli, status);
2507         }
2508         return status;
2509 }
2510
2511 /****************************************************************************
2512  Do a SMBsetatr call.
2513 ****************************************************************************/
2514
2515 static void cli_setatr_done(struct tevent_req *subreq);
2516
2517 struct cli_setatr_state {
2518         uint16_t vwv[8];
2519 };
2520
2521 struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
2522                                 struct event_context *ev,
2523                                 struct cli_state *cli,
2524                                 const char *fname,
2525                                 uint16_t attr,
2526                                 time_t mtime)
2527 {
2528         struct tevent_req *req = NULL, *subreq = NULL;
2529         struct cli_setatr_state *state = NULL;
2530         uint8_t additional_flags = 0;
2531         uint8_t *bytes = NULL;
2532
2533         req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
2534         if (req == NULL) {
2535                 return NULL;
2536         }
2537
2538         memset(state->vwv, '\0', sizeof(state->vwv));
2539         SSVAL(state->vwv+0, 0, attr);
2540         cli_put_dos_date3(cli, (char *)&state->vwv[1], 0, mtime);
2541
2542         bytes = talloc_array(state, uint8_t, 1);
2543         if (tevent_req_nomem(bytes, req)) {
2544                 return tevent_req_post(req, ev);
2545         }
2546         bytes[0] = 4;
2547         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
2548                                    strlen(fname)+1, NULL);
2549         if (tevent_req_nomem(bytes, req)) {
2550                 return tevent_req_post(req, ev);
2551         }
2552         bytes = TALLOC_REALLOC_ARRAY(state, bytes, uint8_t,
2553                         talloc_get_size(bytes)+1);
2554         if (tevent_req_nomem(bytes, req)) {
2555                 return tevent_req_post(req, ev);
2556         }
2557
2558         bytes[talloc_get_size(bytes)-1] = 4;
2559         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",
2560                                    1, NULL);
2561         if (tevent_req_nomem(bytes, req)) {
2562                 return tevent_req_post(req, ev);
2563         }
2564
2565         subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
2566                               8, state->vwv, talloc_get_size(bytes), bytes);
2567         if (tevent_req_nomem(subreq, req)) {
2568                 return tevent_req_post(req, ev);
2569         }
2570         tevent_req_set_callback(subreq, cli_setatr_done, req);
2571         return req;
2572 }
2573
2574 static void cli_setatr_done(struct tevent_req *subreq)
2575 {
2576         struct tevent_req *req = tevent_req_callback_data(
2577                 subreq, struct tevent_req);
2578         NTSTATUS status;
2579
2580         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2581         TALLOC_FREE(subreq);
2582         if (!NT_STATUS_IS_OK(status)) {
2583                 tevent_req_nterror(req, status);
2584                 return;
2585         }
2586         tevent_req_done(req);
2587 }
2588
2589 NTSTATUS cli_setatr_recv(struct tevent_req *req)
2590 {
2591         return tevent_req_simple_recv_ntstatus(req);
2592 }
2593
2594 NTSTATUS cli_setatr(struct cli_state *cli,
2595                 const char *fname,
2596                 uint16_t attr,
2597                 time_t mtime)
2598 {
2599         TALLOC_CTX *frame = talloc_stackframe();
2600         struct event_context *ev = NULL;
2601         struct tevent_req *req = NULL;
2602         NTSTATUS status = NT_STATUS_OK;
2603
2604         if (cli_has_async_calls(cli)) {
2605                 /*
2606                  * Can't use sync call while an async call is in flight
2607                  */
2608                 status = NT_STATUS_INVALID_PARAMETER;
2609                 goto fail;
2610         }
2611
2612         ev = event_context_init(frame);
2613         if (ev == NULL) {
2614                 status = NT_STATUS_NO_MEMORY;
2615                 goto fail;
2616         }
2617
2618         req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
2619         if (req == NULL) {
2620                 status = NT_STATUS_NO_MEMORY;
2621                 goto fail;
2622         }
2623
2624         if (!tevent_req_poll(req, ev)) {
2625                 status = map_nt_error_from_unix(errno);
2626                 goto fail;
2627         }
2628
2629         status = cli_setatr_recv(req);
2630
2631  fail:
2632         TALLOC_FREE(frame);
2633         if (!NT_STATUS_IS_OK(status)) {
2634                 cli_set_error(cli, status);
2635         }
2636         return status;
2637 }
2638
2639 /****************************************************************************
2640  Check for existance of a dir.
2641 ****************************************************************************/
2642
2643 static void cli_chkpath_done(struct tevent_req *subreq);
2644
2645 struct cli_chkpath_state {
2646         int dummy;
2647 };
2648
2649 struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
2650                                   struct event_context *ev,
2651                                   struct cli_state *cli,
2652                                   const char *fname)
2653 {
2654         struct tevent_req *req = NULL, *subreq = NULL;
2655         struct cli_chkpath_state *state = NULL;
2656         uint8_t additional_flags = 0;
2657         uint8_t *bytes = NULL;
2658
2659         req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
2660         if (req == NULL) {
2661                 return NULL;
2662         }
2663
2664         bytes = talloc_array(state, uint8_t, 1);
2665         if (tevent_req_nomem(bytes, req)) {
2666                 return tevent_req_post(req, ev);
2667         }
2668         bytes[0] = 4;
2669         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname,
2670                                    strlen(fname)+1, NULL);
2671
2672         if (tevent_req_nomem(bytes, req)) {
2673                 return tevent_req_post(req, ev);
2674         }
2675
2676         subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
2677                               0, NULL, talloc_get_size(bytes), bytes);
2678         if (tevent_req_nomem(subreq, req)) {
2679                 return tevent_req_post(req, ev);
2680         }
2681         tevent_req_set_callback(subreq, cli_chkpath_done, req);
2682         return req;
2683 }
2684
2685 static void cli_chkpath_done(struct tevent_req *subreq)
2686 {
2687         struct tevent_req *req = tevent_req_callback_data(
2688                 subreq, struct tevent_req);
2689         NTSTATUS status;
2690
2691         status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL);
2692         TALLOC_FREE(subreq);
2693         if (!NT_STATUS_IS_OK(status)) {
2694                 tevent_req_nterror(req, status);
2695                 return;
2696         }
2697         tevent_req_done(req);
2698 }
2699
2700 NTSTATUS cli_chkpath_recv(struct tevent_req *req)
2701 {
2702         return tevent_req_simple_recv_ntstatus(req);
2703 }
2704
2705 NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
2706 {
2707         TALLOC_CTX *frame = talloc_stackframe();
2708         struct event_context *ev = NULL;
2709         struct tevent_req *req = NULL;
2710         char *path2 = NULL;
2711         NTSTATUS status = NT_STATUS_OK;
2712
2713         if (cli_has_async_calls(cli)) {
2714                 /*
2715                  * Can't use sync call while an async call is in flight
2716                  */
2717                 status = NT_STATUS_INVALID_PARAMETER;
2718                 goto fail;
2719         }
2720
2721         path2 = talloc_strdup(frame, path);
2722         if (!path2) {
2723                 status = NT_STATUS_NO_MEMORY;
2724                 goto fail;
2725         }
2726         trim_char(path2,'\0','\\');
2727         if (!*path2) {
2728                 path2 = talloc_strdup(frame, "\\");
2729                 if (!path2) {
2730                         status = NT_STATUS_NO_MEMORY;
2731                         goto fail;
2732                 }
2733         }
2734
2735         ev = event_context_init(frame);
2736         if (ev == NULL) {
2737                 status = NT_STATUS_NO_MEMORY;
2738                 goto fail;
2739         }
2740
2741         req = cli_chkpath_send(frame, ev, cli, path2);
2742         if (req == NULL) {
2743                 status = NT_STATUS_NO_MEMORY;
2744                 goto fail;
2745         }
2746
2747         if (!tevent_req_poll(req, ev)) {
2748                 status = map_nt_error_from_unix(errno);
2749                 goto fail;
2750         }
2751
2752         status = cli_chkpath_recv(req);
2753
2754  fail:
2755         TALLOC_FREE(frame);
2756         if (!NT_STATUS_IS_OK(status)) {
2757                 cli_set_error(cli, status);
2758         }
2759         return status;
2760 }
2761
2762 /****************************************************************************
2763  Query disk space.
2764 ****************************************************************************/
2765
2766 static void cli_dskattr_done(struct tevent_req *subreq);
2767
2768 struct cli_dskattr_state {
2769         int bsize;
2770         int total;
2771         int avail;
2772 };
2773
2774 struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
2775                                   struct event_context *ev,
2776                                   struct cli_state *cli)
2777 {
2778         struct tevent_req *req = NULL, *subreq = NULL;
2779         struct cli_dskattr_state *state = NULL;
2780         uint8_t additional_flags = 0;
2781
2782         req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
2783         if (req == NULL) {
2784                 return NULL;
2785         }
2786
2787         subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags,
2788                               0, NULL, 0, NULL);
2789         if (tevent_req_nomem(subreq, req)) {
2790                 return tevent_req_post(req, ev);
2791         }
2792         tevent_req_set_callback(subreq, cli_dskattr_done, req);
2793         return req;
2794 }
2795
2796 static void cli_dskattr_done(struct tevent_req *subreq)
2797 {
2798         struct tevent_req *req = tevent_req_callback_data(
2799                 subreq, struct tevent_req);
2800         struct cli_dskattr_state *state = tevent_req_data(
2801                 req, struct cli_dskattr_state);
2802         uint8_t wct;
2803         uint16_t *vwv = NULL;
2804         NTSTATUS status;
2805
2806         status = cli_smb_recv(subreq, 4, &wct, &vwv, NULL, NULL);
2807         if (!NT_STATUS_IS_OK(status)) {
2808                 tevent_req_nterror(req, status);
2809                 return;
2810         }
2811         state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
2812         state->total = SVAL(vwv+0, 0);
2813         state->avail = SVAL(vwv+3, 0);
2814         TALLOC_FREE(subreq);
2815         tevent_req_done(req);
2816 }
2817
2818 NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
2819 {
2820         struct cli_dskattr_state *state = tevent_req_data(
2821                                 req, struct cli_dskattr_state);
2822         NTSTATUS status;
2823
2824         if (tevent_req_is_nterror(req, &status)) {
2825                 return status;
2826         }
2827         *bsize = state->bsize;
2828         *total = state->total;
2829         *avail = state->avail;
2830         return NT_STATUS_OK;
2831 }
2832
2833 NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
2834 {
2835         TALLOC_CTX *frame = talloc_stackframe();
2836         struct event_context *ev = NULL;
2837         struct tevent_req *req = NULL;
2838         NTSTATUS status = NT_STATUS_OK;
2839
2840         if (cli_has_async_calls(cli)) {
2841                 /*
2842                  * Can't use sync call while an async call is in flight
2843                  */
2844                 status = NT_STATUS_INVALID_PARAMETER;
2845                 goto fail;
2846         }
2847
2848         ev = event_context_init(frame);
2849         if (ev == NULL) {
2850                 status = NT_STATUS_NO_MEMORY;
2851                 goto fail;
2852         }
2853
2854         req = cli_dskattr_send(frame, ev, cli);
2855         if (req == NULL) {
2856                 status = NT_STATUS_NO_MEMORY;
2857                 goto fail;
2858         }
2859
2860         if (!tevent_req_poll(req, ev)) {
2861                 status = map_nt_error_from_unix(errno);
2862                 goto fail;
2863         }
2864
2865         status = cli_dskattr_recv(req, bsize, total, avail);
2866
2867  fail:
2868         TALLOC_FREE(frame);
2869         if (!NT_STATUS_IS_OK(status)) {
2870                 cli_set_error(cli, status);
2871         }
2872         return status;
2873 }
2874
2875 /****************************************************************************
2876  Create and open a temporary file.
2877 ****************************************************************************/
2878
2879 int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
2880 {
2881         int len;
2882         char *p;
2883
2884         memset(cli->outbuf,'\0',smb_size);
2885         memset(cli->inbuf,'\0',smb_size);
2886
2887         cli_set_message(cli->outbuf,3,0,True);
2888
2889         SCVAL(cli->outbuf,smb_com,SMBctemp);
2890         SSVAL(cli->outbuf,smb_tid,cli->cnum);
2891         cli_setup_packet(cli);
2892
2893         SSVAL(cli->outbuf,smb_vwv0,0);
2894         SIVALS(cli->outbuf,smb_vwv1,-1);
2895
2896         p = smb_buf(cli->outbuf);
2897         *p++ = 4;
2898         p += clistr_push(cli, p, path,
2899                         cli->bufsize - PTR_DIFF(p,cli->outbuf), STR_TERMINATE);
2900
2901         cli_setup_bcc(cli, p);
2902
2903         cli_send_smb(cli);
2904         if (!cli_receive_smb(cli)) {
2905                 return -1;
2906         }
2907
2908         if (cli_is_error(cli)) {
2909                 return -1;
2910         }
2911
2912         /* despite the spec, the result has a -1, followed by
2913            length, followed by name */
2914         p = smb_buf(cli->inbuf);
2915         p += 4;
2916         len = smb_buflen(cli->inbuf) - 4;
2917         if (len <= 0 || len > PATH_MAX) return -1;
2918
2919         if (tmp_path) {
2920                 char *path2 = SMB_MALLOC_ARRAY(char, len+1);
2921                 if (!path2) {
2922                         return -1;
2923                 }
2924                 clistr_pull(cli->inbuf, path2, p,
2925                             len+1, len, STR_ASCII);
2926                 *tmp_path = path2;
2927         }
2928
2929         return SVAL(cli->inbuf,smb_vwv0);
2930 }
2931
2932 /*
2933    send a raw ioctl - used by the torture code
2934 */
2935 NTSTATUS cli_raw_ioctl(struct cli_state *cli, uint16_t fnum, uint32_t code, DATA_BLOB *blob)
2936 {
2937         memset(cli->outbuf,'\0',smb_size);
2938         memset(cli->inbuf,'\0',smb_size);
2939
2940         cli_set_message(cli->outbuf, 3, 0, True);
2941         SCVAL(cli->outbuf,smb_com,SMBioctl);
2942         cli_setup_packet(cli);
2943
2944         SSVAL(cli->outbuf, smb_vwv0, fnum);
2945         SSVAL(cli->outbuf, smb_vwv1, code>>16);
2946         SSVAL(cli->outbuf, smb_vwv2, (code&0xFFFF));
2947
2948         cli_send_smb(cli);
2949         if (!cli_receive_smb(cli)) {
2950                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2951         }
2952
2953         if (cli_is_error(cli)) {
2954                 return cli_nt_error(cli);
2955         }
2956
2957         *blob = data_blob_null;
2958
2959         return NT_STATUS_OK;
2960 }
2961
2962 /*********************************************************
2963  Set an extended attribute utility fn.
2964 *********************************************************/
2965
2966 static bool cli_set_ea(struct cli_state *cli, uint16_t setup, char *param, unsigned int param_len,
2967                         const char *ea_name, const char *ea_val, size_t ea_len)
2968 {
2969         unsigned int data_len = 0;
2970         char *data = NULL;
2971         char *rparam=NULL, *rdata=NULL;
2972         char *p;
2973         size_t ea_namelen = strlen(ea_name);
2974
2975         if (ea_namelen == 0 && ea_len == 0) {
2976                 data_len = 4;
2977                 data = (char *)SMB_MALLOC(data_len);
2978                 if (!data) {
2979                         return False;
2980                 }
2981                 p = data;
2982                 SIVAL(p,0,data_len);
2983         } else {
2984                 data_len = 4 + 4 + ea_namelen + 1 + ea_len;
2985                 data = (char *)SMB_MALLOC(data_len);
2986                 if (!data) {
2987                         return False;
2988                 }
2989                 p = data;
2990                 SIVAL(p,0,data_len);
2991                 p += 4;
2992                 SCVAL(p, 0, 0); /* EA flags. */
2993                 SCVAL(p, 1, ea_namelen);
2994                 SSVAL(p, 2, ea_len);
2995                 memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
2996                 memcpy(p+4+ea_namelen+1, ea_val, ea_len);
2997         }
2998
2999         if (!cli_send_trans(cli, SMBtrans2,
3000                         NULL,                        /* name */
3001                         -1, 0,                          /* fid, flags */
3002                         &setup, 1, 0,                   /* setup, length, max */
3003                         param, param_len, 2,            /* param, length, max */
3004                         data,  data_len, cli->max_xmit /* data, length, max */
3005                         )) {
3006                 SAFE_FREE(data);
3007                 return False;
3008         }
3009
3010         if (!cli_receive_trans(cli, SMBtrans2,
3011                         &rparam, &param_len,
3012                         &rdata, &data_len)) {
3013                         SAFE_FREE(data);
3014                 return false;
3015         }
3016
3017         SAFE_FREE(data);
3018         SAFE_FREE(rdata);
3019         SAFE_FREE(rparam);
3020
3021         return True;
3022 }
3023
3024 /*********************************************************
3025  Set an extended attribute on a pathname.
3026 *********************************************************/
3027
3028 bool cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len)
3029 {
3030         uint16_t setup = TRANSACT2_SETPATHINFO;
3031         unsigned int param_len = 0;
3032         char *param;
3033         size_t srclen = 2*(strlen(path)+1);
3034         char *p;
3035         bool ret;
3036
3037         param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
3038         if (!param) {
3039                 return false;
3040         }
3041         memset(param, '\0', 6);
3042         SSVAL(param,0,SMB_INFO_SET_EA);
3043         p = &param[6];
3044
3045         p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
3046         param_len = PTR_DIFF(p, param);
3047
3048         ret = cli_set_ea(cli, setup, param, param_len, ea_name, ea_val, ea_len);
3049         SAFE_FREE(param);
3050         return ret;
3051 }
3052
3053 /*********************************************************
3054  Set an extended attribute on an fnum.
3055 *********************************************************/
3056
3057 bool cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum, const char *ea_name, const char *ea_val, size_t ea_len)
3058 {
3059         char param[6];
3060         uint16_t setup = TRANSACT2_SETFILEINFO;
3061
3062         memset(param, 0, 6);
3063         SSVAL(param,0,fnum);
3064         SSVAL(param,2,SMB_INFO_SET_EA);
3065
3066         return cli_set_ea(cli, setup, param, 6, ea_name, ea_val, ea_len);
3067 }
3068
3069 /*********************************************************
3070  Get an extended attribute list utility fn.
3071 *********************************************************/
3072
3073 static bool cli_get_ea_list(struct cli_state *cli,
3074                 uint16_t setup, char *param, unsigned int param_len,
3075                 TALLOC_CTX *ctx,
3076                 size_t *pnum_eas,
3077                 struct ea_struct **pea_list)
3078 {
3079         unsigned int data_len = 0;
3080         unsigned int rparam_len, rdata_len;
3081         char *rparam=NULL, *rdata=NULL;
3082         char *p;
3083         size_t ea_size;
3084         size_t num_eas;
3085         bool ret = False;
3086         struct ea_struct *ea_list;
3087
3088         *pnum_eas = 0;
3089         if (pea_list) {
3090                 *pea_list = NULL;
3091         }
3092
3093         if (!cli_send_trans(cli, SMBtrans2,
3094                         NULL,           /* Name */
3095                         -1, 0,          /* fid, flags */
3096                         &setup, 1, 0,   /* setup, length, max */
3097                         param, param_len, 10, /* param, length, max */
3098                         NULL, data_len, cli->max_xmit /* data, length, max */
3099                                 )) {
3100                 return False;
3101         }
3102
3103         if (!cli_receive_trans(cli, SMBtrans2,
3104                         &rparam, &rparam_len,
3105                         &rdata, &rdata_len)) {
3106                 return False;
3107         }
3108
3109         if (!rdata || rdata_len < 4) {
3110                 goto out;
3111         }
3112
3113         ea_size = (size_t)IVAL(rdata,0);
3114         if (ea_size > rdata_len) {
3115                 goto out;
3116         }
3117
3118         if (ea_size == 0) {
3119                 /* No EA's present. */
3120                 ret = True;
3121                 goto out;
3122         }
3123
3124         p = rdata + 4;
3125         ea_size -= 4;
3126
3127         /* Validate the EA list and count it. */
3128         for (num_eas = 0; ea_size >= 4; num_eas++) {
3129                 unsigned int ea_namelen = CVAL(p,1);
3130                 unsigned int ea_valuelen = SVAL(p,2);
3131                 if (ea_namelen == 0) {
3132                         goto out;
3133                 }
3134                 if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
3135                         goto out;
3136                 }
3137                 ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
3138                 p += 4 + ea_namelen + 1 + ea_valuelen;
3139         }
3140
3141         if (num_eas == 0) {
3142                 ret = True;
3143                 goto out;
3144         }
3145
3146         *pnum_eas = num_eas;
3147         if (!pea_list) {
3148                 /* Caller only wants number of EA's. */
3149                 ret = True;
3150                 goto out;
3151         }
3152
3153         ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
3154         if (!ea_list) {
3155                 goto out;
3156         }
3157
3158         ea_size = (size_t)IVAL(rdata,0);
3159         p = rdata + 4;
3160
3161         for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
3162                 struct ea_struct *ea = &ea_list[num_eas];
3163                 fstring unix_ea_name;
3164                 unsigned int ea_namelen = CVAL(p,1);
3165                 unsigned int ea_valuelen = SVAL(p,2);
3166
3167                 ea->flags = CVAL(p,0);
3168                 unix_ea_name[0] = '\0';
3169                 pull_ascii_fstring(unix_ea_name, p + 4);
3170                 ea->name = talloc_strdup(ctx, unix_ea_name);
3171                 /* Ensure the value is null terminated (in case it's a string). */
3172                 ea->value = data_blob_talloc(ctx, NULL, ea_valuelen + 1);
3173                 if (!ea->value.data) {
3174                         goto out;
3175                 }
3176                 if (ea_valuelen) {
3177                         memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
3178                 }
3179                 ea->value.data[ea_valuelen] = 0;
3180                 ea->value.length--;
3181                 p += 4 + ea_namelen + 1 + ea_valuelen;
3182         }
3183
3184         *pea_list = ea_list;
3185         ret = True;
3186
3187  out :
3188
3189         SAFE_FREE(rdata);
3190         SAFE_FREE(rparam);
3191         return ret;
3192 }
3193
3194 /*********************************************************
3195  Get an extended attribute list from a pathname.
3196 *********************************************************/
3197
3198 bool cli_get_ea_list_path(struct cli_state *cli, const char *path,
3199                 TALLOC_CTX *ctx,
3200                 size_t *pnum_eas,
3201                 struct ea_struct **pea_list)
3202 {
3203         uint16_t setup = TRANSACT2_QPATHINFO;
3204         unsigned int param_len = 0;
3205         char *param;
3206         char *p;
3207         size_t srclen = 2*(strlen(path)+1);
3208         bool ret;
3209
3210         param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
3211         if (!param) {
3212                 return false;
3213         }
3214         p = param;
3215         memset(p, 0, 6);
3216         SSVAL(p, 0, SMB_INFO_QUERY_ALL_EAS);
3217         p += 6;
3218         p += clistr_push(cli, p, path, srclen, STR_TERMINATE);
3219         param_len = PTR_DIFF(p, param);
3220
3221         ret = cli_get_ea_list(cli, setup, param, param_len, ctx, pnum_eas, pea_list);
3222         SAFE_FREE(param);
3223         return ret;
3224 }
3225
3226 /*********************************************************
3227  Get an extended attribute list from an fnum.
3228 *********************************************************/
3229
3230 bool cli_get_ea_list_fnum(struct cli_state *cli, uint16_t fnum,
3231                 TALLOC_CTX *ctx,
3232                 size_t *pnum_eas,
3233                 struct ea_struct **pea_list)
3234 {
3235         uint16_t setup = TRANSACT2_QFILEINFO;
3236         char param[6];
3237
3238         memset(param, 0, 6);
3239         SSVAL(param,0,fnum);
3240         SSVAL(param,2,SMB_INFO_SET_EA);
3241
3242         return cli_get_ea_list(cli, setup, param, 6, ctx, pnum_eas, pea_list);
3243 }
3244
3245 /****************************************************************************
3246  Convert open "flags" arg to uint32_t on wire.
3247 ****************************************************************************/
3248
3249 static uint32_t open_flags_to_wire(int flags)
3250 {
3251         int open_mode = flags & O_ACCMODE;
3252         uint32_t ret = 0;
3253
3254         switch (open_mode) {
3255                 case O_WRONLY:
3256                         ret |= SMB_O_WRONLY;
3257                         break;
3258                 case O_RDWR:
3259                         ret |= SMB_O_RDWR;
3260                         break;
3261                 default:
3262                 case O_RDONLY:
3263                         ret |= SMB_O_RDONLY;
3264                         break;
3265         }
3266
3267         if (flags & O_CREAT) {
3268                 ret |= SMB_O_CREAT;
3269         }
3270         if (flags & O_EXCL) {
3271                 ret |= SMB_O_EXCL;
3272         }
3273         if (flags & O_TRUNC) {
3274                 ret |= SMB_O_TRUNC;
3275         }
3276 #if defined(O_SYNC)
3277         if (flags & O_SYNC) {
3278                 ret |= SMB_O_SYNC;
3279         }
3280 #endif /* O_SYNC */
3281         if (flags & O_APPEND) {
3282                 ret |= SMB_O_APPEND;
3283         }
3284 #if defined(O_DIRECT)
3285         if (flags & O_DIRECT) {
3286                 ret |= SMB_O_DIRECT;
3287         }
3288 #endif
3289 #if defined(O_DIRECTORY)
3290         if (flags & O_DIRECTORY) {
3291                 ret &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
3292                 ret |= SMB_O_DIRECTORY;
3293         }
3294 #endif
3295         return ret;
3296 }
3297
3298 /****************************************************************************
3299  Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
3300 ****************************************************************************/
3301
3302 static int cli_posix_open_internal(struct cli_state *cli, const char *fname, int flags, mode_t mode, bool is_dir)
3303 {
3304         unsigned int data_len = 0;
3305         unsigned int param_len = 0;
3306         uint16_t setup = TRANSACT2_SETPATHINFO;
3307         char *param;
3308         char data[18];
3309         char *rparam=NULL, *rdata=NULL;
3310         char *p;
3311         uint16_t fnum = (uint16_t)-1;
3312         uint32_t wire_flags = open_flags_to_wire(flags);
3313         size_t srclen = 2*(strlen(fname)+1);
3314
3315         param = SMB_MALLOC_ARRAY(char, 6+srclen+2);
3316         if (!param) {
3317                 return false;
3318         }
3319         memset(param, '\0', 6);
3320         SSVAL(param,0, SMB_POSIX_PATH_OPEN);
3321         p = &param[6];
3322
3323         p += clistr_push(cli, p, fname, srclen, STR_TERMINATE);
3324         param_len = PTR_DIFF(p, param);
3325
3326         if (is_dir) {
3327                 wire_flags &= ~(SMB_O_RDONLY|SMB_O_RDWR|SMB_O_WRONLY);
3328                 wire_flags |= SMB_O_DIRECTORY;
3329         }
3330
3331         p = data;
3332         SIVAL(p,0,0); /* No oplock. */
3333         SIVAL(p,4,wire_flags);
3334         SIVAL(p,8,unix_perms_to_wire(mode));
3335         SIVAL(p,12,0); /* Top bits of perms currently undefined. */
3336         SSVAL(p,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
3337
3338         data_len = 18;
3339
3340         if (!cli_send_trans(cli, SMBtrans2,
3341                         NULL,                        /* name */
3342                         -1, 0,                          /* fid, flags */
3343                         &setup, 1, 0,                   /* setup, length, max */
3344                         param, param_len, 0,            /* param, length, max */
3345                         (char *)&data,  data_len, cli->max_xmit /* data, length, max */
3346                         )) {
3347                 SAFE_FREE(param);
3348                 return -1;
3349         }
3350
3351         SAFE_FREE(param);
3352
3353         if (!cli_receive_trans(cli, SMBtrans2,
3354                 &rparam, &param_len,
3355                 &rdata, &data_len)) {
3356                         return -1;
3357         }
3358
3359         fnum = SVAL(rdata,2);
3360
3361         SAFE_FREE(rdata);
3362         SAFE_FREE(rparam);
3363
3364         return fnum;
3365 }
3366
3367 /****************************************************************************
3368  open - POSIX semantics.
3369 ****************************************************************************/
3370
3371 int cli_posix_open(struct cli_state *cli, const char *fname, int flags, mode_t mode)
3372 {
3373         return cli_posix_open_internal(cli, fname, flags, mode, False);
3374 }
3375
3376 /****************************************************************************
3377  mkdir - POSIX semantics.
3378 ****************************************************************************/
3379
3380 int cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
3381 {
3382         return (cli_posix_open_internal(cli, fname, O_CREAT, mode, True) == -1) ? -1 : 0;
3383 }
3384
3385 /****************************************************************************
3386  unlink or rmdir - POSIX semantics.
3387 ****************************************************************************/
3388
3389 struct unlink_state {
3390         uint16_t setup;
3391         uint8_t data[2];
3392 };
3393
3394 static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
3395 {
3396         struct tevent_req *req = tevent_req_callback_data(
3397                                 subreq, struct tevent_req);
3398         struct unlink_state *state = tevent_req_data(req, struct unlink_state);
3399         NTSTATUS status;
3400
3401         status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, NULL, NULL);
3402         TALLOC_FREE(subreq);
3403         if (!NT_STATUS_IS_OK(status)) {
3404                 tevent_req_nterror(req, status);
3405                 return;
3406         }
3407         tevent_req_done(req);
3408 }
3409
3410 static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
3411                                         struct event_context *ev,
3412                                         struct cli_state *cli,
3413                                         const char *fname,
3414                                         bool is_dir)
3415 {
3416         struct tevent_req *req = NULL, *subreq = NULL;
3417         struct unlink_state *state = NULL;
3418         uint8_t *param = NULL;
3419
3420         req = tevent_req_create(mem_ctx, &state, struct unlink_state);
3421         if (req == NULL) {
3422                 return NULL;
3423         }
3424
3425         /* Setup setup word. */
3426         SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
3427
3428         /* Setup param array. */
3429         param = talloc_array(state, uint8_t, 6);