source: vendor/current/source3/libsmb/clifile.c

Last change on this file was 989, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.7

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