s3:libsmb: remove unused smb2cli.h
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
bloba099e034d8825c880a47732e34683324cb0175e8
1 /*
2 Unix SMB/CIFS implementation.
3 smb2 lib
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
29 #include "includes.h"
30 #include "client.h"
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
34 #include "trans2.h"
35 #include "clirap.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "lib/util_ea.h"
42 struct smb2_hnd {
43 uint64_t fid_persistent;
44 uint64_t fid_volatile;
48 * Handle mapping code.
51 /***************************************************************
52 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
53 Ensures handle is owned by cli struct.
54 ***************************************************************/
56 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
57 const struct smb2_hnd *ph, /* In */
58 uint16_t *pfnum) /* Out */
60 int ret;
61 struct idr_context *idp = cli->smb2.open_handles;
62 struct smb2_hnd *owned_h = talloc_memdup(cli,
63 ph,
64 sizeof(struct smb2_hnd));
66 if (owned_h == NULL) {
67 return NT_STATUS_NO_MEMORY;
70 if (idp == NULL) {
71 /* Lazy init */
72 cli->smb2.open_handles = idr_init(cli);
73 if (cli->smb2.open_handles == NULL) {
74 TALLOC_FREE(owned_h);
75 return NT_STATUS_NO_MEMORY;
77 idp = cli->smb2.open_handles;
80 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
81 if (ret == -1) {
82 TALLOC_FREE(owned_h);
83 return NT_STATUS_NO_MEMORY;
86 *pfnum = (uint16_t)ret;
87 return NT_STATUS_OK;
90 /***************************************************************
91 Return the smb2_hnd pointer associated with the given fnum.
92 ***************************************************************/
94 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
95 uint16_t fnum, /* In */
96 struct smb2_hnd **pph) /* Out */
98 struct idr_context *idp = cli->smb2.open_handles;
100 if (idp == NULL) {
101 return NT_STATUS_INVALID_PARAMETER;
103 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
104 if (*pph == NULL) {
105 return NT_STATUS_INVALID_HANDLE;
107 return NT_STATUS_OK;
110 /***************************************************************
111 Delete the fnum to smb2_hnd mapping. Zeros out handle on
112 successful return.
113 ***************************************************************/
115 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
116 struct smb2_hnd **pph, /* In */
117 uint16_t fnum) /* In */
119 struct idr_context *idp = cli->smb2.open_handles;
120 struct smb2_hnd *ph;
122 if (idp == NULL) {
123 return NT_STATUS_INVALID_PARAMETER;
126 ph = (struct smb2_hnd *)idr_find(idp, fnum);
127 if (ph != *pph) {
128 return NT_STATUS_INVALID_PARAMETER;
130 idr_remove(idp, fnum);
131 TALLOC_FREE(*pph);
132 return NT_STATUS_OK;
135 /***************************************************************
136 Oplock mapping code.
137 ***************************************************************/
139 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
141 if (create_flags & REQUEST_BATCH_OPLOCK) {
142 return SMB2_OPLOCK_LEVEL_BATCH;
143 } else if (create_flags & REQUEST_OPLOCK) {
144 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
147 /* create_flags doesn't do a level2 request. */
148 return SMB2_OPLOCK_LEVEL_NONE;
151 /***************************************************************
152 Small wrapper that allows SMB2 create to return a uint16_t fnum.
153 ***************************************************************/
155 struct cli_smb2_create_fnum_state {
156 struct cli_state *cli;
157 struct smb_create_returns cr;
158 uint16_t fnum;
159 struct tevent_req *subreq;
162 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
163 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
165 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
166 struct tevent_context *ev,
167 struct cli_state *cli,
168 const char *fname,
169 uint32_t create_flags,
170 uint32_t desired_access,
171 uint32_t file_attributes,
172 uint32_t share_access,
173 uint32_t create_disposition,
174 uint32_t create_options)
176 struct tevent_req *req, *subreq;
177 struct cli_smb2_create_fnum_state *state;
179 req = tevent_req_create(mem_ctx, &state,
180 struct cli_smb2_create_fnum_state);
181 if (req == NULL) {
182 return NULL;
184 state->cli = cli;
186 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
187 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
188 return tevent_req_post(req, ev);
191 if (cli->backup_intent) {
192 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
195 /* SMB2 is pickier about pathnames. Ensure it doesn't
196 start in a '\' */
197 if (*fname == '\\') {
198 fname++;
201 subreq = smb2cli_create_send(state, ev,
202 cli->conn,
203 cli->timeout,
204 cli->smb2.session,
205 cli->smb2.tcon,
206 fname,
207 flags_to_smb2_oplock(create_flags),
208 SMB2_IMPERSONATION_IMPERSONATION,
209 desired_access,
210 file_attributes,
211 share_access,
212 create_disposition,
213 create_options,
214 NULL);
215 if (tevent_req_nomem(subreq, req)) {
216 return tevent_req_post(req, ev);
218 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
220 state->subreq = subreq;
221 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
223 return req;
226 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
228 struct tevent_req *req = tevent_req_callback_data(
229 subreq, struct tevent_req);
230 struct cli_smb2_create_fnum_state *state = tevent_req_data(
231 req, struct cli_smb2_create_fnum_state);
232 struct smb2_hnd h;
233 NTSTATUS status;
235 status = smb2cli_create_recv(subreq, &h.fid_persistent,
236 &h.fid_volatile, &state->cr, NULL, NULL);
237 TALLOC_FREE(subreq);
238 if (tevent_req_nterror(req, status)) {
239 return;
242 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
243 if (tevent_req_nterror(req, status)) {
244 return;
246 tevent_req_done(req);
249 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
251 struct cli_smb2_create_fnum_state *state = tevent_req_data(
252 req, struct cli_smb2_create_fnum_state);
253 return tevent_req_cancel(state->subreq);
256 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
257 struct smb_create_returns *cr)
259 struct cli_smb2_create_fnum_state *state = tevent_req_data(
260 req, struct cli_smb2_create_fnum_state);
261 NTSTATUS status;
263 if (tevent_req_is_nterror(req, &status)) {
264 return status;
266 if (pfnum != NULL) {
267 *pfnum = state->fnum;
269 if (cr != NULL) {
270 *cr = state->cr;
272 return NT_STATUS_OK;
275 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
276 const char *fname,
277 uint32_t create_flags,
278 uint32_t desired_access,
279 uint32_t file_attributes,
280 uint32_t share_access,
281 uint32_t create_disposition,
282 uint32_t create_options,
283 uint16_t *pfid,
284 struct smb_create_returns *cr)
286 TALLOC_CTX *frame = talloc_stackframe();
287 struct tevent_context *ev;
288 struct tevent_req *req;
289 NTSTATUS status = NT_STATUS_NO_MEMORY;
291 if (smbXcli_conn_has_async_calls(cli->conn)) {
293 * Can't use sync call while an async call is in flight
295 status = NT_STATUS_INVALID_PARAMETER;
296 goto fail;
298 ev = samba_tevent_context_init(frame);
299 if (ev == NULL) {
300 goto fail;
302 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
303 desired_access, file_attributes,
304 share_access, create_disposition,
305 create_options);
306 if (req == NULL) {
307 goto fail;
309 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
310 goto fail;
312 status = cli_smb2_create_fnum_recv(req, pfid, cr);
313 fail:
314 TALLOC_FREE(frame);
315 return status;
318 /***************************************************************
319 Small wrapper that allows SMB2 close to use a uint16_t fnum.
320 ***************************************************************/
322 struct cli_smb2_close_fnum_state {
323 struct cli_state *cli;
324 uint16_t fnum;
325 struct smb2_hnd *ph;
328 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
330 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
331 struct tevent_context *ev,
332 struct cli_state *cli,
333 uint16_t fnum)
335 struct tevent_req *req, *subreq;
336 struct cli_smb2_close_fnum_state *state;
337 NTSTATUS status;
339 req = tevent_req_create(mem_ctx, &state,
340 struct cli_smb2_close_fnum_state);
341 if (req == NULL) {
342 return NULL;
344 state->cli = cli;
345 state->fnum = fnum;
347 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
348 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
349 return tevent_req_post(req, ev);
352 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
353 if (tevent_req_nterror(req, status)) {
354 return tevent_req_post(req, ev);
357 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
358 cli->smb2.session, cli->smb2.tcon,
359 0, state->ph->fid_persistent,
360 state->ph->fid_volatile);
361 if (tevent_req_nomem(subreq, req)) {
362 return tevent_req_post(req, ev);
364 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
365 return req;
368 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
370 struct tevent_req *req = tevent_req_callback_data(
371 subreq, struct tevent_req);
372 struct cli_smb2_close_fnum_state *state = tevent_req_data(
373 req, struct cli_smb2_close_fnum_state);
374 NTSTATUS status;
376 status = smb2cli_close_recv(subreq);
377 if (tevent_req_nterror(req, status)) {
378 return;
381 /* Delete the fnum -> handle mapping. */
382 status = delete_smb2_handle_mapping(state->cli, &state->ph,
383 state->fnum);
384 if (tevent_req_nterror(req, status)) {
385 return;
387 tevent_req_done(req);
390 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
392 return tevent_req_simple_recv_ntstatus(req);
395 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
397 TALLOC_CTX *frame = talloc_stackframe();
398 struct tevent_context *ev;
399 struct tevent_req *req;
400 NTSTATUS status = NT_STATUS_NO_MEMORY;
402 if (smbXcli_conn_has_async_calls(cli->conn)) {
404 * Can't use sync call while an async call is in flight
406 status = NT_STATUS_INVALID_PARAMETER;
407 goto fail;
409 ev = samba_tevent_context_init(frame);
410 if (ev == NULL) {
411 goto fail;
413 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
414 if (req == NULL) {
415 goto fail;
417 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
418 goto fail;
420 status = cli_smb2_close_fnum_recv(req);
421 fail:
422 TALLOC_FREE(frame);
423 return status;
426 /***************************************************************
427 Small wrapper that allows SMB2 to create a directory
428 Synchronous only.
429 ***************************************************************/
431 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
433 NTSTATUS status;
434 uint16_t fnum;
436 if (smbXcli_conn_has_async_calls(cli->conn)) {
438 * Can't use sync call while an async call is in flight
440 return NT_STATUS_INVALID_PARAMETER;
443 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
444 return NT_STATUS_INVALID_PARAMETER;
447 status = cli_smb2_create_fnum(cli,
448 dname,
449 0, /* create_flags */
450 FILE_READ_ATTRIBUTES, /* desired_access */
451 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
452 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
453 FILE_CREATE, /* create_disposition */
454 FILE_DIRECTORY_FILE, /* create_options */
455 &fnum,
456 NULL);
458 if (!NT_STATUS_IS_OK(status)) {
459 return status;
461 return cli_smb2_close_fnum(cli, fnum);
464 /***************************************************************
465 Small wrapper that allows SMB2 to delete a directory
466 Synchronous only.
467 ***************************************************************/
469 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
471 NTSTATUS status;
472 uint16_t fnum;
474 if (smbXcli_conn_has_async_calls(cli->conn)) {
476 * Can't use sync call while an async call is in flight
478 return NT_STATUS_INVALID_PARAMETER;
481 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
482 return NT_STATUS_INVALID_PARAMETER;
485 status = cli_smb2_create_fnum(cli,
486 dname,
487 0, /* create_flags */
488 DELETE_ACCESS, /* desired_access */
489 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
490 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
491 FILE_OPEN, /* create_disposition */
492 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
493 &fnum,
494 NULL);
496 if (!NT_STATUS_IS_OK(status)) {
497 return status;
499 return cli_smb2_close_fnum(cli, fnum);
502 /***************************************************************
503 Small wrapper that allows SMB2 to unlink a pathname.
504 Synchronous only.
505 ***************************************************************/
507 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
509 NTSTATUS status;
510 uint16_t fnum;
512 if (smbXcli_conn_has_async_calls(cli->conn)) {
514 * Can't use sync call while an async call is in flight
516 return NT_STATUS_INVALID_PARAMETER;
519 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
520 return NT_STATUS_INVALID_PARAMETER;
523 status = cli_smb2_create_fnum(cli,
524 fname,
525 0, /* create_flags */
526 DELETE_ACCESS, /* desired_access */
527 FILE_ATTRIBUTE_NORMAL, /* file attributes */
528 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
529 FILE_OPEN, /* create_disposition */
530 FILE_DELETE_ON_CLOSE, /* create_options */
531 &fnum,
532 NULL);
534 if (!NT_STATUS_IS_OK(status)) {
535 return status;
537 return cli_smb2_close_fnum(cli, fnum);
540 /***************************************************************
541 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
542 ***************************************************************/
544 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
545 uint32_t dir_data_length,
546 struct file_info *finfo,
547 uint32_t *next_offset)
549 size_t namelen = 0;
550 size_t slen = 0;
551 size_t ret = 0;
553 if (dir_data_length < 4) {
554 return NT_STATUS_INFO_LENGTH_MISMATCH;
557 *next_offset = IVAL(dir_data, 0);
559 if (*next_offset > dir_data_length) {
560 return NT_STATUS_INFO_LENGTH_MISMATCH;
563 if (*next_offset != 0) {
564 /* Ensure we only read what in this record. */
565 dir_data_length = *next_offset;
568 if (dir_data_length < 105) {
569 return NT_STATUS_INFO_LENGTH_MISMATCH;
572 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
573 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
574 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
575 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
576 finfo->mode = CVAL(dir_data + 56, 0);
577 namelen = IVAL(dir_data + 60,0);
578 if (namelen > (dir_data_length - 104)) {
579 return NT_STATUS_INFO_LENGTH_MISMATCH;
581 slen = CVAL(dir_data + 68, 0);
582 if (slen > 24) {
583 return NT_STATUS_INFO_LENGTH_MISMATCH;
585 ret = pull_string_talloc(finfo,
586 dir_data,
587 FLAGS2_UNICODE_STRINGS,
588 &finfo->short_name,
589 dir_data + 70,
590 slen,
591 STR_UNICODE);
592 if (ret == (size_t)-1) {
593 /* Bad conversion. */
594 return NT_STATUS_INVALID_NETWORK_RESPONSE;
597 ret = pull_string_talloc(finfo,
598 dir_data,
599 FLAGS2_UNICODE_STRINGS,
600 &finfo->name,
601 dir_data + 104,
602 namelen,
603 STR_UNICODE);
604 if (ret == (size_t)-1) {
605 /* Bad conversion. */
606 return NT_STATUS_INVALID_NETWORK_RESPONSE;
608 return NT_STATUS_OK;
611 /*******************************************************************
612 Given a filename - get its directory name
613 ********************************************************************/
615 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
616 const char *dir,
617 char **parent,
618 const char **name)
620 char *p;
621 ptrdiff_t len;
623 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
625 if (p == NULL) {
626 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
627 return false;
629 if (name) {
630 *name = dir;
632 return true;
635 len = p-dir;
637 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
638 return false;
640 (*parent)[len] = '\0';
642 if (name) {
643 *name = p+1;
645 return true;
648 /***************************************************************
649 Wrapper that allows SMB2 to list a directory.
650 Synchronous only.
651 ***************************************************************/
653 NTSTATUS cli_smb2_list(struct cli_state *cli,
654 const char *pathname,
655 uint16_t attribute,
656 NTSTATUS (*fn)(const char *,
657 struct file_info *,
658 const char *,
659 void *),
660 void *state)
662 NTSTATUS status;
663 uint16_t fnum = 0xffff;
664 char *parent_dir = NULL;
665 const char *mask = NULL;
666 struct smb2_hnd *ph = NULL;
667 bool processed_file = false;
668 TALLOC_CTX *frame = talloc_stackframe();
669 TALLOC_CTX *subframe = NULL;
671 if (smbXcli_conn_has_async_calls(cli->conn)) {
673 * Can't use sync call while an async call is in flight
675 status = NT_STATUS_INVALID_PARAMETER;
676 goto fail;
679 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
680 status = NT_STATUS_INVALID_PARAMETER;
681 goto fail;
684 /* Get the directory name. */
685 if (!windows_parent_dirname(frame,
686 pathname,
687 &parent_dir,
688 &mask)) {
689 status = NT_STATUS_NO_MEMORY;
690 goto fail;
693 status = cli_smb2_create_fnum(cli,
694 parent_dir,
695 0, /* create_flags */
696 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
697 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
698 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
699 FILE_OPEN, /* create_disposition */
700 FILE_DIRECTORY_FILE, /* create_options */
701 &fnum,
702 NULL);
704 if (!NT_STATUS_IS_OK(status)) {
705 goto fail;
708 status = map_fnum_to_smb2_handle(cli,
709 fnum,
710 &ph);
711 if (!NT_STATUS_IS_OK(status)) {
712 goto fail;
715 do {
716 uint8_t *dir_data = NULL;
717 uint32_t dir_data_length = 0;
718 uint32_t next_offset = 0;
719 subframe = talloc_stackframe();
721 status = smb2cli_query_directory(cli->conn,
722 cli->timeout,
723 cli->smb2.session,
724 cli->smb2.tcon,
725 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
726 0, /* flags */
727 0, /* file_index */
728 ph->fid_persistent,
729 ph->fid_volatile,
730 mask,
731 0xffff,
732 subframe,
733 &dir_data,
734 &dir_data_length);
736 if (!NT_STATUS_IS_OK(status)) {
737 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
738 break;
740 goto fail;
743 do {
744 struct file_info *finfo = talloc_zero(subframe,
745 struct file_info);
747 if (finfo == NULL) {
748 status = NT_STATUS_NO_MEMORY;
749 goto fail;
752 status = parse_finfo_id_both_directory_info(dir_data,
753 dir_data_length,
754 finfo,
755 &next_offset);
757 if (!NT_STATUS_IS_OK(status)) {
758 goto fail;
761 if (dir_check_ftype((uint32_t)finfo->mode,
762 (uint32_t)attribute)) {
764 * Only process if attributes match.
765 * On SMB1 server does this, so on
766 * SMB2 we need to emulate in the
767 * client.
769 * https://bugzilla.samba.org/show_bug.cgi?id=10260
771 processed_file = true;
773 status = fn(cli->dfs_mountpoint,
774 finfo,
775 pathname,
776 state);
778 if (!NT_STATUS_IS_OK(status)) {
779 break;
783 TALLOC_FREE(finfo);
785 /* Move to next entry. */
786 if (next_offset) {
787 dir_data += next_offset;
788 dir_data_length -= next_offset;
790 } while (next_offset != 0);
792 TALLOC_FREE(subframe);
794 } while (NT_STATUS_IS_OK(status));
796 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
797 status = NT_STATUS_OK;
800 if (NT_STATUS_IS_OK(status) && !processed_file) {
802 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
803 * if no files match. Emulate this in the client.
805 status = NT_STATUS_NO_SUCH_FILE;
808 fail:
810 if (fnum != 0xffff) {
811 cli_smb2_close_fnum(cli, fnum);
813 TALLOC_FREE(subframe);
814 TALLOC_FREE(frame);
815 return status;
818 /***************************************************************
819 Wrapper that allows SMB2 to query a path info (basic level).
820 Synchronous only.
821 ***************************************************************/
823 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
824 const char *name,
825 SMB_STRUCT_STAT *sbuf,
826 uint32_t *attributes)
828 NTSTATUS status;
829 struct smb_create_returns cr;
830 uint16_t fnum = 0xffff;
831 size_t namelen = strlen(name);
833 if (smbXcli_conn_has_async_calls(cli->conn)) {
835 * Can't use sync call while an async call is in flight
837 return NT_STATUS_INVALID_PARAMETER;
840 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
841 return NT_STATUS_INVALID_PARAMETER;
844 /* SMB2 is pickier about pathnames. Ensure it doesn't
845 end in a '\' */
846 if (namelen > 0 && name[namelen-1] == '\\') {
847 char *modname = talloc_strdup(talloc_tos(), name);
848 modname[namelen-1] = '\0';
849 name = modname;
852 /* This is commonly used as a 'cd'. Try qpathinfo on
853 a directory handle first. */
855 status = cli_smb2_create_fnum(cli,
856 name,
857 0, /* create_flags */
858 FILE_READ_ATTRIBUTES, /* desired_access */
859 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
860 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
861 FILE_OPEN, /* create_disposition */
862 FILE_DIRECTORY_FILE, /* create_options */
863 &fnum,
864 &cr);
866 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
867 /* Maybe a file ? */
868 status = cli_smb2_create_fnum(cli,
869 name,
870 0, /* create_flags */
871 FILE_READ_ATTRIBUTES, /* desired_access */
872 0, /* file attributes */
873 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
874 FILE_OPEN, /* create_disposition */
875 0, /* create_options */
876 &fnum,
877 &cr);
880 if (!NT_STATUS_IS_OK(status)) {
881 return status;
884 cli_smb2_close_fnum(cli, fnum);
886 ZERO_STRUCTP(sbuf);
888 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
889 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
890 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
891 sbuf->st_ex_size = cr.end_of_file;
892 *attributes = cr.file_attributes;
894 return NT_STATUS_OK;
897 /***************************************************************
898 Helper function for pathname operations.
899 ***************************************************************/
901 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
902 const char *name,
903 uint32_t desired_access,
904 uint16_t *pfnum)
906 NTSTATUS status;
907 size_t namelen = strlen(name);
908 TALLOC_CTX *frame = talloc_stackframe();
910 /* SMB2 is pickier about pathnames. Ensure it doesn't
911 end in a '\' */
912 if (namelen > 0 && name[namelen-1] == '\\') {
913 char *modname = talloc_strdup(frame, name);
914 if (modname == NULL) {
915 status = NT_STATUS_NO_MEMORY;
916 goto fail;
918 modname[namelen-1] = '\0';
919 name = modname;
922 /* Try to open a file handle first. */
923 status = cli_smb2_create_fnum(cli,
924 name,
925 0, /* create_flags */
926 desired_access,
927 0, /* file attributes */
928 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
929 FILE_OPEN, /* create_disposition */
930 0, /* create_options */
931 pfnum,
932 NULL);
934 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
935 status = cli_smb2_create_fnum(cli,
936 name,
937 0, /* create_flags */
938 desired_access,
939 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
940 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
941 FILE_OPEN, /* create_disposition */
942 FILE_DIRECTORY_FILE, /* create_options */
943 pfnum,
944 NULL);
947 fail:
949 TALLOC_FREE(frame);
950 return status;
953 /***************************************************************
954 Wrapper that allows SMB2 to query a path info (ALTNAME level).
955 Synchronous only.
956 ***************************************************************/
958 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
959 const char *name,
960 fstring alt_name)
962 NTSTATUS status;
963 DATA_BLOB outbuf = data_blob_null;
964 uint16_t fnum = 0xffff;
965 struct smb2_hnd *ph = NULL;
966 uint32_t altnamelen = 0;
967 TALLOC_CTX *frame = talloc_stackframe();
969 if (smbXcli_conn_has_async_calls(cli->conn)) {
971 * Can't use sync call while an async call is in flight
973 status = NT_STATUS_INVALID_PARAMETER;
974 goto fail;
977 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
978 status = NT_STATUS_INVALID_PARAMETER;
979 goto fail;
982 status = get_fnum_from_path(cli,
983 name,
984 FILE_READ_ATTRIBUTES,
985 &fnum);
987 if (!NT_STATUS_IS_OK(status)) {
988 goto fail;
991 status = map_fnum_to_smb2_handle(cli,
992 fnum,
993 &ph);
994 if (!NT_STATUS_IS_OK(status)) {
995 goto fail;
998 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
999 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1001 status = smb2cli_query_info(cli->conn,
1002 cli->timeout,
1003 cli->smb2.session,
1004 cli->smb2.tcon,
1005 1, /* in_info_type */
1006 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1007 0xFFFF, /* in_max_output_length */
1008 NULL, /* in_input_buffer */
1009 0, /* in_additional_info */
1010 0, /* in_flags */
1011 ph->fid_persistent,
1012 ph->fid_volatile,
1013 frame,
1014 &outbuf);
1016 if (!NT_STATUS_IS_OK(status)) {
1017 goto fail;
1020 /* Parse the reply. */
1021 if (outbuf.length < 4) {
1022 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1023 goto fail;
1026 altnamelen = IVAL(outbuf.data, 0);
1027 if (altnamelen > outbuf.length - 4) {
1028 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1029 goto fail;
1032 if (altnamelen > 0) {
1033 size_t ret = 0;
1034 char *short_name = NULL;
1035 ret = pull_string_talloc(frame,
1036 outbuf.data,
1037 FLAGS2_UNICODE_STRINGS,
1038 &short_name,
1039 outbuf.data + 4,
1040 altnamelen,
1041 STR_UNICODE);
1042 if (ret == (size_t)-1) {
1043 /* Bad conversion. */
1044 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1045 goto fail;
1048 fstrcpy(alt_name, short_name);
1049 } else {
1050 alt_name[0] = '\0';
1053 status = NT_STATUS_OK;
1055 fail:
1057 if (fnum != 0xffff) {
1058 cli_smb2_close_fnum(cli, fnum);
1060 TALLOC_FREE(frame);
1061 return status;
1065 /***************************************************************
1066 Wrapper that allows SMB2 to query a fnum info (basic level).
1067 Synchronous only.
1068 ***************************************************************/
1070 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1071 uint16_t fnum,
1072 uint16_t *mode,
1073 off_t *size,
1074 struct timespec *create_time,
1075 struct timespec *access_time,
1076 struct timespec *write_time,
1077 struct timespec *change_time,
1078 SMB_INO_T *ino)
1080 NTSTATUS status;
1081 DATA_BLOB outbuf = data_blob_null;
1082 struct smb2_hnd *ph = NULL;
1083 TALLOC_CTX *frame = talloc_stackframe();
1085 if (smbXcli_conn_has_async_calls(cli->conn)) {
1087 * Can't use sync call while an async call is in flight
1089 status = NT_STATUS_INVALID_PARAMETER;
1090 goto fail;
1093 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1094 status = NT_STATUS_INVALID_PARAMETER;
1095 goto fail;
1098 status = map_fnum_to_smb2_handle(cli,
1099 fnum,
1100 &ph);
1101 if (!NT_STATUS_IS_OK(status)) {
1102 goto fail;
1105 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1106 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1108 status = smb2cli_query_info(cli->conn,
1109 cli->timeout,
1110 cli->smb2.session,
1111 cli->smb2.tcon,
1112 1, /* in_info_type */
1113 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1114 0xFFFF, /* in_max_output_length */
1115 NULL, /* in_input_buffer */
1116 0, /* in_additional_info */
1117 0, /* in_flags */
1118 ph->fid_persistent,
1119 ph->fid_volatile,
1120 frame,
1121 &outbuf);
1122 if (!NT_STATUS_IS_OK(status)) {
1123 goto fail;
1126 /* Parse the reply. */
1127 if (outbuf.length < 0x60) {
1128 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1129 goto fail;
1132 if (create_time) {
1133 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1135 if (access_time) {
1136 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1138 if (write_time) {
1139 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1141 if (change_time) {
1142 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1144 if (mode) {
1145 uint32_t attr = IVAL(outbuf.data, 0x20);
1146 *mode = (uint16_t)attr;
1148 if (size) {
1149 uint64_t file_size = BVAL(outbuf.data, 0x30);
1150 *size = (off_t)file_size;
1152 if (ino) {
1153 uint64_t file_index = BVAL(outbuf.data, 0x40);
1154 *ino = (SMB_INO_T)file_index;
1157 fail:
1159 TALLOC_FREE(frame);
1160 return status;
1163 /***************************************************************
1164 Wrapper that allows SMB2 to query an fnum.
1165 Implement on top of cli_smb2_qfileinfo_basic().
1166 Synchronous only.
1167 ***************************************************************/
1169 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1170 uint16_t fnum,
1171 uint16_t *attr,
1172 off_t *size,
1173 time_t *change_time,
1174 time_t *access_time,
1175 time_t *write_time)
1177 struct timespec access_time_ts;
1178 struct timespec write_time_ts;
1179 struct timespec change_time_ts;
1180 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1181 fnum,
1182 attr,
1183 size,
1184 NULL,
1185 &access_time_ts,
1186 &write_time_ts,
1187 &change_time_ts,
1188 NULL);
1190 if (!NT_STATUS_IS_OK(status)) {
1191 return status;
1194 if (change_time) {
1195 *change_time = change_time_ts.tv_sec;
1197 if (access_time) {
1198 *access_time = access_time_ts.tv_sec;
1200 if (write_time) {
1201 *write_time = write_time_ts.tv_sec;
1203 return NT_STATUS_OK;
1206 /***************************************************************
1207 Wrapper that allows SMB2 to get pathname attributes.
1208 Synchronous only.
1209 ***************************************************************/
1211 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1212 const char *name,
1213 uint16_t *attr,
1214 off_t *size,
1215 time_t *write_time)
1217 NTSTATUS status;
1218 uint16_t fnum = 0xffff;
1219 struct smb2_hnd *ph = NULL;
1220 TALLOC_CTX *frame = talloc_stackframe();
1222 if (smbXcli_conn_has_async_calls(cli->conn)) {
1224 * Can't use sync call while an async call is in flight
1226 status = NT_STATUS_INVALID_PARAMETER;
1227 goto fail;
1230 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1231 status = NT_STATUS_INVALID_PARAMETER;
1232 goto fail;
1235 status = get_fnum_from_path(cli,
1236 name,
1237 FILE_READ_ATTRIBUTES,
1238 &fnum);
1240 if (!NT_STATUS_IS_OK(status)) {
1241 goto fail;
1244 status = map_fnum_to_smb2_handle(cli,
1245 fnum,
1246 &ph);
1247 if (!NT_STATUS_IS_OK(status)) {
1248 goto fail;
1250 status = cli_smb2_getattrE(cli,
1251 fnum,
1252 attr,
1253 size,
1254 NULL,
1255 NULL,
1256 write_time);
1257 if (!NT_STATUS_IS_OK(status)) {
1258 goto fail;
1261 fail:
1263 if (fnum != 0xffff) {
1264 cli_smb2_close_fnum(cli, fnum);
1267 TALLOC_FREE(frame);
1268 return status;
1271 /***************************************************************
1272 Wrapper that allows SMB2 to query a pathname info (basic level).
1273 Implement on top of cli_smb2_qfileinfo_basic().
1274 Synchronous only.
1275 ***************************************************************/
1277 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1278 const char *name,
1279 struct timespec *create_time,
1280 struct timespec *access_time,
1281 struct timespec *write_time,
1282 struct timespec *change_time,
1283 off_t *size,
1284 uint16_t *mode,
1285 SMB_INO_T *ino)
1287 NTSTATUS status;
1288 struct smb2_hnd *ph = NULL;
1289 uint16_t fnum = 0xffff;
1290 TALLOC_CTX *frame = talloc_stackframe();
1292 if (smbXcli_conn_has_async_calls(cli->conn)) {
1294 * Can't use sync call while an async call is in flight
1296 status = NT_STATUS_INVALID_PARAMETER;
1297 goto fail;
1300 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1301 status = NT_STATUS_INVALID_PARAMETER;
1302 goto fail;
1305 status = get_fnum_from_path(cli,
1306 name,
1307 FILE_READ_ATTRIBUTES,
1308 &fnum);
1310 if (!NT_STATUS_IS_OK(status)) {
1311 goto fail;
1314 status = map_fnum_to_smb2_handle(cli,
1315 fnum,
1316 &ph);
1317 if (!NT_STATUS_IS_OK(status)) {
1318 goto fail;
1321 status = cli_smb2_qfileinfo_basic(cli,
1322 fnum,
1323 mode,
1324 size,
1325 create_time,
1326 access_time,
1327 write_time,
1328 change_time,
1329 ino);
1331 fail:
1333 if (fnum != 0xffff) {
1334 cli_smb2_close_fnum(cli, fnum);
1337 TALLOC_FREE(frame);
1338 return status;
1341 /***************************************************************
1342 Wrapper that allows SMB2 to query pathname streams.
1343 Synchronous only.
1344 ***************************************************************/
1346 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1347 const char *name,
1348 TALLOC_CTX *mem_ctx,
1349 unsigned int *pnum_streams,
1350 struct stream_struct **pstreams)
1352 NTSTATUS status;
1353 struct smb2_hnd *ph = NULL;
1354 uint16_t fnum = 0xffff;
1355 DATA_BLOB outbuf = data_blob_null;
1356 TALLOC_CTX *frame = talloc_stackframe();
1358 if (smbXcli_conn_has_async_calls(cli->conn)) {
1360 * Can't use sync call while an async call is in flight
1362 status = NT_STATUS_INVALID_PARAMETER;
1363 goto fail;
1366 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1367 status = NT_STATUS_INVALID_PARAMETER;
1368 goto fail;
1371 status = get_fnum_from_path(cli,
1372 name,
1373 FILE_READ_ATTRIBUTES,
1374 &fnum);
1376 if (!NT_STATUS_IS_OK(status)) {
1377 goto fail;
1380 status = map_fnum_to_smb2_handle(cli,
1381 fnum,
1382 &ph);
1383 if (!NT_STATUS_IS_OK(status)) {
1384 goto fail;
1387 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1388 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1390 status = smb2cli_query_info(cli->conn,
1391 cli->timeout,
1392 cli->smb2.session,
1393 cli->smb2.tcon,
1394 1, /* in_info_type */
1395 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1396 0xFFFF, /* in_max_output_length */
1397 NULL, /* in_input_buffer */
1398 0, /* in_additional_info */
1399 0, /* in_flags */
1400 ph->fid_persistent,
1401 ph->fid_volatile,
1402 frame,
1403 &outbuf);
1405 if (!NT_STATUS_IS_OK(status)) {
1406 goto fail;
1409 /* Parse the reply. */
1410 if (!parse_streams_blob(mem_ctx,
1411 outbuf.data,
1412 outbuf.length,
1413 pnum_streams,
1414 pstreams)) {
1415 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1416 goto fail;
1419 fail:
1421 if (fnum != 0xffff) {
1422 cli_smb2_close_fnum(cli, fnum);
1425 TALLOC_FREE(frame);
1426 return status;
1429 /***************************************************************
1430 Wrapper that allows SMB2 to set pathname attributes.
1431 Synchronous only.
1432 ***************************************************************/
1434 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1435 const char *name,
1436 uint16_t attr,
1437 time_t mtime)
1439 NTSTATUS status;
1440 uint16_t fnum = 0xffff;
1441 struct smb2_hnd *ph = NULL;
1442 uint8_t inbuf_store[40];
1443 DATA_BLOB inbuf = data_blob_null;
1444 TALLOC_CTX *frame = talloc_stackframe();
1446 if (smbXcli_conn_has_async_calls(cli->conn)) {
1448 * Can't use sync call while an async call is in flight
1450 status = NT_STATUS_INVALID_PARAMETER;
1451 goto fail;
1454 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1455 status = NT_STATUS_INVALID_PARAMETER;
1456 goto fail;
1459 status = get_fnum_from_path(cli,
1460 name,
1461 FILE_WRITE_ATTRIBUTES,
1462 &fnum);
1464 if (!NT_STATUS_IS_OK(status)) {
1465 goto fail;
1468 status = map_fnum_to_smb2_handle(cli,
1469 fnum,
1470 &ph);
1471 if (!NT_STATUS_IS_OK(status)) {
1472 goto fail;
1475 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1476 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1478 inbuf.data = inbuf_store;
1479 inbuf.length = sizeof(inbuf_store);
1480 data_blob_clear(&inbuf);
1482 SSVAL(inbuf.data, 32, attr);
1483 if (mtime != 0) {
1484 put_long_date((char *)inbuf.data + 16,mtime);
1486 /* Set all the other times to -1. */
1487 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1488 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1489 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1491 status = smb2cli_set_info(cli->conn,
1492 cli->timeout,
1493 cli->smb2.session,
1494 cli->smb2.tcon,
1495 1, /* in_info_type */
1496 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1497 &inbuf, /* in_input_buffer */
1498 0, /* in_additional_info */
1499 ph->fid_persistent,
1500 ph->fid_volatile);
1501 fail:
1503 if (fnum != 0xffff) {
1504 cli_smb2_close_fnum(cli, fnum);
1507 TALLOC_FREE(frame);
1508 return status;
1511 /***************************************************************
1512 Wrapper that allows SMB2 to set file handle times.
1513 Synchronous only.
1514 ***************************************************************/
1516 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1517 uint16_t fnum,
1518 time_t change_time,
1519 time_t access_time,
1520 time_t write_time)
1522 NTSTATUS status;
1523 struct smb2_hnd *ph = NULL;
1524 uint8_t inbuf_store[40];
1525 DATA_BLOB inbuf = data_blob_null;
1527 if (smbXcli_conn_has_async_calls(cli->conn)) {
1529 * Can't use sync call while an async call is in flight
1531 return NT_STATUS_INVALID_PARAMETER;
1534 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1535 return NT_STATUS_INVALID_PARAMETER;
1538 status = map_fnum_to_smb2_handle(cli,
1539 fnum,
1540 &ph);
1541 if (!NT_STATUS_IS_OK(status)) {
1542 return status;
1545 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1546 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1548 inbuf.data = inbuf_store;
1549 inbuf.length = sizeof(inbuf_store);
1550 data_blob_clear(&inbuf);
1552 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1553 if (change_time != 0) {
1554 put_long_date((char *)inbuf.data + 24, change_time);
1556 if (access_time != 0) {
1557 put_long_date((char *)inbuf.data + 8, access_time);
1559 if (write_time != 0) {
1560 put_long_date((char *)inbuf.data + 16, write_time);
1563 return smb2cli_set_info(cli->conn,
1564 cli->timeout,
1565 cli->smb2.session,
1566 cli->smb2.tcon,
1567 1, /* in_info_type */
1568 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1569 &inbuf, /* in_input_buffer */
1570 0, /* in_additional_info */
1571 ph->fid_persistent,
1572 ph->fid_volatile);
1575 /***************************************************************
1576 Wrapper that allows SMB2 to query disk attributes (size).
1577 Synchronous only.
1578 ***************************************************************/
1580 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, uint64_t *bsize, uint64_t *total, uint64_t *avail)
1582 NTSTATUS status;
1583 uint16_t fnum = 0xffff;
1584 DATA_BLOB outbuf = data_blob_null;
1585 struct smb2_hnd *ph = NULL;
1586 uint32_t sectors_per_unit = 0;
1587 uint32_t bytes_per_sector = 0;
1588 uint64_t total_size = 0;
1589 uint64_t size_free = 0;
1590 TALLOC_CTX *frame = talloc_stackframe();
1592 if (smbXcli_conn_has_async_calls(cli->conn)) {
1594 * Can't use sync call while an async call is in flight
1596 status = NT_STATUS_INVALID_PARAMETER;
1597 goto fail;
1600 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1601 status = NT_STATUS_INVALID_PARAMETER;
1602 goto fail;
1605 /* First open the top level directory. */
1606 status = cli_smb2_create_fnum(cli,
1608 0, /* create_flags */
1609 FILE_READ_ATTRIBUTES, /* desired_access */
1610 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1611 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1612 FILE_OPEN, /* create_disposition */
1613 FILE_DIRECTORY_FILE, /* create_options */
1614 &fnum,
1615 NULL);
1617 if (!NT_STATUS_IS_OK(status)) {
1618 goto fail;
1621 status = map_fnum_to_smb2_handle(cli,
1622 fnum,
1623 &ph);
1624 if (!NT_STATUS_IS_OK(status)) {
1625 goto fail;
1628 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1629 level 3 (SMB_FS_SIZE_INFORMATION). */
1631 status = smb2cli_query_info(cli->conn,
1632 cli->timeout,
1633 cli->smb2.session,
1634 cli->smb2.tcon,
1635 2, /* in_info_type */
1636 3, /* in_file_info_class */
1637 0xFFFF, /* in_max_output_length */
1638 NULL, /* in_input_buffer */
1639 0, /* in_additional_info */
1640 0, /* in_flags */
1641 ph->fid_persistent,
1642 ph->fid_volatile,
1643 frame,
1644 &outbuf);
1645 if (!NT_STATUS_IS_OK(status)) {
1646 goto fail;
1649 /* Parse the reply. */
1650 if (outbuf.length != 24) {
1651 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1652 goto fail;
1655 total_size = BVAL(outbuf.data, 0);
1656 size_free = BVAL(outbuf.data, 8);
1657 sectors_per_unit = IVAL(outbuf.data, 16);
1658 bytes_per_sector = IVAL(outbuf.data, 20);
1660 if (bsize) {
1661 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1663 if (total) {
1664 *total = total_size;
1666 if (avail) {
1667 *avail = size_free;
1670 status = NT_STATUS_OK;
1672 fail:
1674 if (fnum != 0xffff) {
1675 cli_smb2_close_fnum(cli, fnum);
1678 TALLOC_FREE(frame);
1679 return status;
1682 /***************************************************************
1683 Wrapper that allows SMB2 to query a security descriptor.
1684 Synchronous only.
1685 ***************************************************************/
1687 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1688 uint16_t fnum,
1689 uint32_t sec_info,
1690 TALLOC_CTX *mem_ctx,
1691 struct security_descriptor **ppsd)
1693 NTSTATUS status;
1694 DATA_BLOB outbuf = data_blob_null;
1695 struct smb2_hnd *ph = NULL;
1696 struct security_descriptor *lsd = NULL;
1697 TALLOC_CTX *frame = talloc_stackframe();
1699 if (smbXcli_conn_has_async_calls(cli->conn)) {
1701 * Can't use sync call while an async call is in flight
1703 status = NT_STATUS_INVALID_PARAMETER;
1704 goto fail;
1707 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1708 status = NT_STATUS_INVALID_PARAMETER;
1709 goto fail;
1712 status = map_fnum_to_smb2_handle(cli,
1713 fnum,
1714 &ph);
1715 if (!NT_STATUS_IS_OK(status)) {
1716 goto fail;
1719 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1721 status = smb2cli_query_info(cli->conn,
1722 cli->timeout,
1723 cli->smb2.session,
1724 cli->smb2.tcon,
1725 3, /* in_info_type */
1726 0, /* in_file_info_class */
1727 0xFFFF, /* in_max_output_length */
1728 NULL, /* in_input_buffer */
1729 sec_info, /* in_additional_info */
1730 0, /* in_flags */
1731 ph->fid_persistent,
1732 ph->fid_volatile,
1733 frame,
1734 &outbuf);
1736 if (!NT_STATUS_IS_OK(status)) {
1737 goto fail;
1740 /* Parse the reply. */
1741 status = unmarshall_sec_desc(mem_ctx,
1742 outbuf.data,
1743 outbuf.length,
1744 &lsd);
1746 if (!NT_STATUS_IS_OK(status)) {
1747 goto fail;
1750 if (ppsd != NULL) {
1751 *ppsd = lsd;
1752 } else {
1753 TALLOC_FREE(lsd);
1756 fail:
1758 TALLOC_FREE(frame);
1759 return status;
1762 /***************************************************************
1763 Wrapper that allows SMB2 to set a security descriptor.
1764 Synchronous only.
1765 ***************************************************************/
1767 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1768 uint16_t fnum,
1769 uint32_t sec_info,
1770 const struct security_descriptor *sd)
1772 NTSTATUS status;
1773 DATA_BLOB inbuf = data_blob_null;
1774 struct smb2_hnd *ph = NULL;
1775 TALLOC_CTX *frame = talloc_stackframe();
1777 if (smbXcli_conn_has_async_calls(cli->conn)) {
1779 * Can't use sync call while an async call is in flight
1781 status = NT_STATUS_INVALID_PARAMETER;
1782 goto fail;
1785 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1786 status = NT_STATUS_INVALID_PARAMETER;
1787 goto fail;
1790 status = map_fnum_to_smb2_handle(cli,
1791 fnum,
1792 &ph);
1793 if (!NT_STATUS_IS_OK(status)) {
1794 goto fail;
1797 status = marshall_sec_desc(frame,
1799 &inbuf.data,
1800 &inbuf.length);
1802 if (!NT_STATUS_IS_OK(status)) {
1803 goto fail;
1806 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1808 status = smb2cli_set_info(cli->conn,
1809 cli->timeout,
1810 cli->smb2.session,
1811 cli->smb2.tcon,
1812 3, /* in_info_type */
1813 0, /* in_file_info_class */
1814 &inbuf, /* in_input_buffer */
1815 sec_info, /* in_additional_info */
1816 ph->fid_persistent,
1817 ph->fid_volatile);
1819 fail:
1821 TALLOC_FREE(frame);
1822 return status;
1825 /***************************************************************
1826 Wrapper that allows SMB2 to rename a file.
1827 Synchronous only.
1828 ***************************************************************/
1830 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1831 const char *fname_src,
1832 const char *fname_dst)
1834 NTSTATUS status;
1835 DATA_BLOB inbuf = data_blob_null;
1836 uint16_t fnum = 0xffff;
1837 struct smb2_hnd *ph = NULL;
1838 smb_ucs2_t *converted_str = NULL;
1839 size_t converted_size_bytes = 0;
1840 size_t namelen = 0;
1841 TALLOC_CTX *frame = talloc_stackframe();
1843 if (smbXcli_conn_has_async_calls(cli->conn)) {
1845 * Can't use sync call while an async call is in flight
1847 status = NT_STATUS_INVALID_PARAMETER;
1848 goto fail;
1851 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1852 status = NT_STATUS_INVALID_PARAMETER;
1853 goto fail;
1856 status = get_fnum_from_path(cli,
1857 fname_src,
1858 DELETE_ACCESS,
1859 &fnum);
1861 if (!NT_STATUS_IS_OK(status)) {
1862 goto fail;
1865 status = map_fnum_to_smb2_handle(cli,
1866 fnum,
1867 &ph);
1868 if (!NT_STATUS_IS_OK(status)) {
1869 goto fail;
1872 /* SMB2 is pickier about pathnames. Ensure it doesn't
1873 start in a '\' */
1874 if (*fname_dst == '\\') {
1875 fname_dst++;
1878 /* SMB2 is pickier about pathnames. Ensure it doesn't
1879 end in a '\' */
1880 namelen = strlen(fname_dst);
1881 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
1882 char *modname = talloc_strdup(frame, fname_dst);
1883 modname[namelen-1] = '\0';
1884 fname_dst = modname;
1887 if (!push_ucs2_talloc(frame,
1888 &converted_str,
1889 fname_dst,
1890 &converted_size_bytes)) {
1891 status = NT_STATUS_INVALID_PARAMETER;
1892 goto fail;
1895 /* W2K8 insists the dest name is not null
1896 terminated. Remove the last 2 zero bytes
1897 and reduce the name length. */
1899 if (converted_size_bytes < 2) {
1900 status = NT_STATUS_INVALID_PARAMETER;
1901 goto fail;
1903 converted_size_bytes -= 2;
1905 inbuf = data_blob_talloc_zero(frame,
1906 20 + converted_size_bytes);
1907 if (inbuf.data == NULL) {
1908 status = NT_STATUS_NO_MEMORY;
1909 goto fail;
1912 SIVAL(inbuf.data, 16, converted_size_bytes);
1913 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
1915 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1916 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1918 status = smb2cli_set_info(cli->conn,
1919 cli->timeout,
1920 cli->smb2.session,
1921 cli->smb2.tcon,
1922 1, /* in_info_type */
1923 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
1924 &inbuf, /* in_input_buffer */
1925 0, /* in_additional_info */
1926 ph->fid_persistent,
1927 ph->fid_volatile);
1929 fail:
1931 if (fnum != 0xffff) {
1932 cli_smb2_close_fnum(cli, fnum);
1935 TALLOC_FREE(frame);
1936 return status;
1939 /***************************************************************
1940 Wrapper that allows SMB2 to set an EA on a fnum.
1941 Synchronous only.
1942 ***************************************************************/
1944 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
1945 uint16_t fnum,
1946 const char *ea_name,
1947 const char *ea_val,
1948 size_t ea_len)
1950 NTSTATUS status;
1951 DATA_BLOB inbuf = data_blob_null;
1952 size_t bloblen = 0;
1953 char *ea_name_ascii = NULL;
1954 size_t namelen = 0;
1955 struct smb2_hnd *ph = NULL;
1956 TALLOC_CTX *frame = talloc_stackframe();
1958 if (smbXcli_conn_has_async_calls(cli->conn)) {
1960 * Can't use sync call while an async call is in flight
1962 status = NT_STATUS_INVALID_PARAMETER;
1963 goto fail;
1966 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1967 status = NT_STATUS_INVALID_PARAMETER;
1968 goto fail;
1971 status = map_fnum_to_smb2_handle(cli,
1972 fnum,
1973 &ph);
1974 if (!NT_STATUS_IS_OK(status)) {
1975 goto fail;
1978 /* Marshall the SMB2 EA data. */
1979 if (ea_len > 0xFFFF) {
1980 status = NT_STATUS_INVALID_PARAMETER;
1981 goto fail;
1984 if (!push_ascii_talloc(frame,
1985 &ea_name_ascii,
1986 ea_name,
1987 &namelen)) {
1988 status = NT_STATUS_INVALID_PARAMETER;
1989 goto fail;
1992 if (namelen < 2 || namelen > 0xFF) {
1993 status = NT_STATUS_INVALID_PARAMETER;
1994 goto fail;
1997 bloblen = 8 + ea_len + namelen;
1998 /* Round up to a 4 byte boundary. */
1999 bloblen = ((bloblen + 3)&~3);
2001 inbuf = data_blob_talloc_zero(frame, bloblen);
2002 if (inbuf.data == NULL) {
2003 status = NT_STATUS_NO_MEMORY;
2004 goto fail;
2006 /* namelen doesn't include the NULL byte. */
2007 SCVAL(inbuf.data, 5, namelen - 1);
2008 SSVAL(inbuf.data, 6, ea_len);
2009 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2010 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2012 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2013 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2015 status = smb2cli_set_info(cli->conn,
2016 cli->timeout,
2017 cli->smb2.session,
2018 cli->smb2.tcon,
2019 1, /* in_info_type */
2020 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2021 &inbuf, /* in_input_buffer */
2022 0, /* in_additional_info */
2023 ph->fid_persistent,
2024 ph->fid_volatile);
2026 fail:
2028 TALLOC_FREE(frame);
2029 return status;
2032 /***************************************************************
2033 Wrapper that allows SMB2 to set an EA on a pathname.
2034 Synchronous only.
2035 ***************************************************************/
2037 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2038 const char *name,
2039 const char *ea_name,
2040 const char *ea_val,
2041 size_t ea_len)
2043 NTSTATUS status;
2044 uint16_t fnum = 0xffff;
2046 if (smbXcli_conn_has_async_calls(cli->conn)) {
2048 * Can't use sync call while an async call is in flight
2050 status = NT_STATUS_INVALID_PARAMETER;
2051 goto fail;
2054 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2055 status = NT_STATUS_INVALID_PARAMETER;
2056 goto fail;
2059 status = get_fnum_from_path(cli,
2060 name,
2061 FILE_WRITE_EA,
2062 &fnum);
2064 if (!NT_STATUS_IS_OK(status)) {
2065 goto fail;
2068 status = cli_set_ea_fnum(cli,
2069 fnum,
2070 ea_name,
2071 ea_val,
2072 ea_len);
2073 if (!NT_STATUS_IS_OK(status)) {
2074 goto fail;
2077 fail:
2079 if (fnum != 0xffff) {
2080 cli_smb2_close_fnum(cli, fnum);
2083 return status;
2086 /***************************************************************
2087 Wrapper that allows SMB2 to get an EA list on a pathname.
2088 Synchronous only.
2089 ***************************************************************/
2091 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2092 const char *name,
2093 TALLOC_CTX *ctx,
2094 size_t *pnum_eas,
2095 struct ea_struct **pea_array)
2097 NTSTATUS status;
2098 uint16_t fnum = 0xffff;
2099 DATA_BLOB outbuf = data_blob_null;
2100 struct smb2_hnd *ph = NULL;
2101 struct ea_list *ea_list = NULL;
2102 struct ea_list *eal = NULL;
2103 size_t ea_count = 0;
2104 TALLOC_CTX *frame = talloc_stackframe();
2106 *pnum_eas = 0;
2107 *pea_array = NULL;
2109 if (smbXcli_conn_has_async_calls(cli->conn)) {
2111 * Can't use sync call while an async call is in flight
2113 status = NT_STATUS_INVALID_PARAMETER;
2114 goto fail;
2117 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2118 status = NT_STATUS_INVALID_PARAMETER;
2119 goto fail;
2122 status = get_fnum_from_path(cli,
2123 name,
2124 FILE_READ_EA,
2125 &fnum);
2127 if (!NT_STATUS_IS_OK(status)) {
2128 goto fail;
2131 status = map_fnum_to_smb2_handle(cli,
2132 fnum,
2133 &ph);
2134 if (!NT_STATUS_IS_OK(status)) {
2135 goto fail;
2138 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2139 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2141 status = smb2cli_query_info(cli->conn,
2142 cli->timeout,
2143 cli->smb2.session,
2144 cli->smb2.tcon,
2145 1, /* in_info_type */
2146 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2147 0xFFFF, /* in_max_output_length */
2148 NULL, /* in_input_buffer */
2149 0, /* in_additional_info */
2150 0, /* in_flags */
2151 ph->fid_persistent,
2152 ph->fid_volatile,
2153 frame,
2154 &outbuf);
2156 if (!NT_STATUS_IS_OK(status)) {
2157 goto fail;
2160 /* Parse the reply. */
2161 ea_list = read_nttrans_ea_list(ctx,
2162 (const char *)outbuf.data,
2163 outbuf.length);
2164 if (ea_list == NULL) {
2165 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2166 goto fail;
2169 /* Convert to an array. */
2170 for (eal = ea_list; eal; eal = eal->next) {
2171 ea_count++;
2174 if (ea_count) {
2175 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2176 if (*pea_array == NULL) {
2177 status = NT_STATUS_NO_MEMORY;
2178 goto fail;
2180 ea_count = 0;
2181 for (eal = ea_list; eal; eal = eal->next) {
2182 (*pea_array)[ea_count++] = ea_list->ea;
2184 *pnum_eas = ea_count;
2187 fail:
2189 if (fnum != 0xffff) {
2190 cli_smb2_close_fnum(cli, fnum);
2193 TALLOC_FREE(frame);
2194 return status;
2197 struct cli_smb2_read_state {
2198 struct tevent_context *ev;
2199 struct cli_state *cli;
2200 struct smb2_hnd *ph;
2201 uint64_t start_offset;
2202 uint32_t size;
2203 uint32_t received;
2204 uint8_t *buf;
2207 static void cli_smb2_read_done(struct tevent_req *subreq);
2209 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2210 struct tevent_context *ev,
2211 struct cli_state *cli,
2212 uint16_t fnum,
2213 off_t offset,
2214 size_t size)
2216 NTSTATUS status;
2217 struct tevent_req *req, *subreq;
2218 struct cli_smb2_read_state *state;
2220 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2221 if (req == NULL) {
2222 return NULL;
2224 state->ev = ev;
2225 state->cli = cli;
2226 state->start_offset = (uint64_t)offset;
2227 state->size = (uint32_t)size;
2228 state->received = 0;
2229 state->buf = NULL;
2231 status = map_fnum_to_smb2_handle(cli,
2232 fnum,
2233 &state->ph);
2234 if (tevent_req_nterror(req, status)) {
2235 return tevent_req_post(req, ev);
2238 subreq = smb2cli_read_send(state,
2239 state->ev,
2240 state->cli->conn,
2241 state->cli->timeout,
2242 state->cli->smb2.session,
2243 state->cli->smb2.tcon,
2244 state->size,
2245 state->start_offset,
2246 state->ph->fid_persistent,
2247 state->ph->fid_volatile,
2248 0, /* minimum_count */
2249 0); /* remaining_bytes */
2251 if (tevent_req_nomem(subreq, req)) {
2252 return tevent_req_post(req, ev);
2254 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2255 return req;
2258 static void cli_smb2_read_done(struct tevent_req *subreq)
2260 struct tevent_req *req = tevent_req_callback_data(
2261 subreq, struct tevent_req);
2262 struct cli_smb2_read_state *state = tevent_req_data(
2263 req, struct cli_smb2_read_state);
2264 NTSTATUS status;
2266 status = smb2cli_read_recv(subreq, state,
2267 &state->buf, &state->received);
2268 if (tevent_req_nterror(req, status)) {
2269 return;
2272 if (state->received > state->size) {
2273 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2274 return;
2277 tevent_req_done(req);
2280 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2281 ssize_t *received,
2282 uint8_t **rcvbuf)
2284 NTSTATUS status;
2285 struct cli_smb2_read_state *state = tevent_req_data(
2286 req, struct cli_smb2_read_state);
2288 if (tevent_req_is_nterror(req, &status)) {
2289 return status;
2292 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2293 * better make sure that you copy it away before you talloc_free(req).
2294 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2296 *received = (ssize_t)state->received;
2297 *rcvbuf = state->buf;
2298 return NT_STATUS_OK;
2301 struct cli_smb2_write_state {
2302 struct tevent_context *ev;
2303 struct cli_state *cli;
2304 struct smb2_hnd *ph;
2305 uint32_t flags;
2306 const uint8_t *buf;
2307 uint64_t offset;
2308 uint32_t size;
2309 uint32_t written;
2312 static void cli_smb2_write_written(struct tevent_req *req);
2314 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2315 struct tevent_context *ev,
2316 struct cli_state *cli,
2317 uint16_t fnum,
2318 uint16_t mode,
2319 const uint8_t *buf,
2320 off_t offset,
2321 size_t size)
2323 NTSTATUS status;
2324 struct tevent_req *req, *subreq = NULL;
2325 struct cli_smb2_write_state *state = NULL;
2327 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2328 if (req == NULL) {
2329 return NULL;
2331 state->ev = ev;
2332 state->cli = cli;
2333 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2334 state->flags = (uint32_t)mode;
2335 state->buf = buf;
2336 state->offset = (uint64_t)offset;
2337 state->size = (uint32_t)size;
2338 state->written = 0;
2340 status = map_fnum_to_smb2_handle(cli,
2341 fnum,
2342 &state->ph);
2343 if (tevent_req_nterror(req, status)) {
2344 return tevent_req_post(req, ev);
2347 subreq = smb2cli_write_send(state,
2348 state->ev,
2349 state->cli->conn,
2350 state->cli->timeout,
2351 state->cli->smb2.session,
2352 state->cli->smb2.tcon,
2353 state->size,
2354 state->offset,
2355 state->ph->fid_persistent,
2356 state->ph->fid_volatile,
2357 0, /* remaining_bytes */
2358 state->flags, /* flags */
2359 state->buf);
2361 if (tevent_req_nomem(subreq, req)) {
2362 return tevent_req_post(req, ev);
2364 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2365 return req;
2368 static void cli_smb2_write_written(struct tevent_req *subreq)
2370 struct tevent_req *req = tevent_req_callback_data(
2371 subreq, struct tevent_req);
2372 struct cli_smb2_write_state *state = tevent_req_data(
2373 req, struct cli_smb2_write_state);
2374 NTSTATUS status;
2375 uint32_t written;
2377 status = smb2cli_write_recv(subreq, &written);
2378 TALLOC_FREE(subreq);
2379 if (tevent_req_nterror(req, status)) {
2380 return;
2383 state->written = written;
2385 tevent_req_done(req);
2388 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2389 size_t *pwritten)
2391 struct cli_smb2_write_state *state = tevent_req_data(
2392 req, struct cli_smb2_write_state);
2393 NTSTATUS status;
2395 if (tevent_req_is_nterror(req, &status)) {
2396 tevent_req_received(req);
2397 return status;
2400 if (pwritten != NULL) {
2401 *pwritten = (size_t)state->written;
2403 tevent_req_received(req);
2404 return NT_STATUS_OK;
2407 /***************************************************************
2408 Wrapper that allows SMB2 async write using an fnum.
2409 This is mostly cut-and-paste from Volker's code inside
2410 source3/libsmb/clireadwrite.c, adapted for SMB2.
2412 Done this way so I can reuse all the logic inside cli_push()
2413 for free :-).
2414 ***************************************************************/
2416 struct cli_smb2_writeall_state {
2417 struct tevent_context *ev;
2418 struct cli_state *cli;
2419 struct smb2_hnd *ph;
2420 uint32_t flags;
2421 const uint8_t *buf;
2422 uint64_t offset;
2423 uint32_t size;
2424 uint32_t written;
2427 static void cli_smb2_writeall_written(struct tevent_req *req);
2429 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2430 struct tevent_context *ev,
2431 struct cli_state *cli,
2432 uint16_t fnum,
2433 uint16_t mode,
2434 const uint8_t *buf,
2435 off_t offset,
2436 size_t size)
2438 NTSTATUS status;
2439 struct tevent_req *req, *subreq = NULL;
2440 struct cli_smb2_writeall_state *state = NULL;
2441 uint32_t to_write;
2442 uint32_t max_size;
2443 bool ok;
2445 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2446 if (req == NULL) {
2447 return NULL;
2449 state->ev = ev;
2450 state->cli = cli;
2451 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2452 state->flags = (uint32_t)mode;
2453 state->buf = buf;
2454 state->offset = (uint64_t)offset;
2455 state->size = (uint32_t)size;
2456 state->written = 0;
2458 status = map_fnum_to_smb2_handle(cli,
2459 fnum,
2460 &state->ph);
2461 if (tevent_req_nterror(req, status)) {
2462 return tevent_req_post(req, ev);
2465 to_write = state->size;
2466 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2467 to_write = MIN(max_size, to_write);
2468 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2469 if (ok) {
2470 to_write = MIN(max_size, to_write);
2473 subreq = smb2cli_write_send(state,
2474 state->ev,
2475 state->cli->conn,
2476 state->cli->timeout,
2477 state->cli->smb2.session,
2478 state->cli->smb2.tcon,
2479 to_write,
2480 state->offset,
2481 state->ph->fid_persistent,
2482 state->ph->fid_volatile,
2483 0, /* remaining_bytes */
2484 state->flags, /* flags */
2485 state->buf + state->written);
2487 if (tevent_req_nomem(subreq, req)) {
2488 return tevent_req_post(req, ev);
2490 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2491 return req;
2494 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2496 struct tevent_req *req = tevent_req_callback_data(
2497 subreq, struct tevent_req);
2498 struct cli_smb2_writeall_state *state = tevent_req_data(
2499 req, struct cli_smb2_writeall_state);
2500 NTSTATUS status;
2501 uint32_t written, to_write;
2502 uint32_t max_size;
2503 bool ok;
2505 status = smb2cli_write_recv(subreq, &written);
2506 TALLOC_FREE(subreq);
2507 if (tevent_req_nterror(req, status)) {
2508 return;
2511 state->written += written;
2513 if (state->written > state->size) {
2514 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2515 return;
2518 to_write = state->size - state->written;
2520 if (to_write == 0) {
2521 tevent_req_done(req);
2522 return;
2525 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2526 to_write = MIN(max_size, to_write);
2527 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2528 if (ok) {
2529 to_write = MIN(max_size, to_write);
2532 subreq = smb2cli_write_send(state,
2533 state->ev,
2534 state->cli->conn,
2535 state->cli->timeout,
2536 state->cli->smb2.session,
2537 state->cli->smb2.tcon,
2538 to_write,
2539 state->offset + state->written,
2540 state->ph->fid_persistent,
2541 state->ph->fid_volatile,
2542 0, /* remaining_bytes */
2543 state->flags, /* flags */
2544 state->buf + state->written);
2546 if (tevent_req_nomem(subreq, req)) {
2547 return;
2549 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2552 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
2553 size_t *pwritten)
2555 struct cli_smb2_writeall_state *state = tevent_req_data(
2556 req, struct cli_smb2_writeall_state);
2557 NTSTATUS status;
2559 if (tevent_req_is_nterror(req, &status)) {
2560 return status;
2562 if (pwritten != NULL) {
2563 *pwritten = (size_t)state->written;
2565 return NT_STATUS_OK;