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