libsmb: Make cli_smb2_create_fnum cancellable
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blob87edf4e29820a8ff647cd89627bb2e80995e4feb
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 "smb2cli.h"
34 #include "cli_smb2_fnum.h"
35 #include "trans2.h"
36 #include "clirap.h"
37 #include "../libcli/smb/smb2_create_blob.h"
38 #include "libsmb/proto.h"
39 #include "lib/util/tevent_ntstatus.h"
40 #include "../libcli/security/security.h"
41 #include "lib/util_ea.h"
43 struct smb2_hnd {
44 uint64_t fid_persistent;
45 uint64_t fid_volatile;
49 * Handle mapping code.
52 /***************************************************************
53 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
54 Ensures handle is owned by cli struct.
55 ***************************************************************/
57 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
58 const struct smb2_hnd *ph, /* In */
59 uint16_t *pfnum) /* Out */
61 int ret;
62 struct idr_context *idp = cli->smb2.open_handles;
63 struct smb2_hnd *owned_h = talloc_memdup(cli,
64 ph,
65 sizeof(struct smb2_hnd));
67 if (owned_h == NULL) {
68 return NT_STATUS_NO_MEMORY;
71 if (idp == NULL) {
72 /* Lazy init */
73 cli->smb2.open_handles = idr_init(cli);
74 if (cli->smb2.open_handles == NULL) {
75 TALLOC_FREE(owned_h);
76 return NT_STATUS_NO_MEMORY;
78 idp = cli->smb2.open_handles;
81 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
82 if (ret == -1) {
83 TALLOC_FREE(owned_h);
84 return NT_STATUS_NO_MEMORY;
87 *pfnum = (uint16_t)ret;
88 return NT_STATUS_OK;
91 /***************************************************************
92 Return the smb2_hnd pointer associated with the given fnum.
93 ***************************************************************/
95 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
96 uint16_t fnum, /* In */
97 struct smb2_hnd **pph) /* Out */
99 struct idr_context *idp = cli->smb2.open_handles;
101 if (idp == NULL) {
102 return NT_STATUS_INVALID_PARAMETER;
104 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
105 if (*pph == NULL) {
106 return NT_STATUS_INVALID_HANDLE;
108 return NT_STATUS_OK;
111 /***************************************************************
112 Delete the fnum to smb2_hnd mapping. Zeros out handle on
113 successful return.
114 ***************************************************************/
116 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
117 struct smb2_hnd **pph, /* In */
118 uint16_t fnum) /* In */
120 struct idr_context *idp = cli->smb2.open_handles;
121 struct smb2_hnd *ph;
123 if (idp == NULL) {
124 return NT_STATUS_INVALID_PARAMETER;
127 ph = (struct smb2_hnd *)idr_find(idp, fnum);
128 if (ph != *pph) {
129 return NT_STATUS_INVALID_PARAMETER;
131 idr_remove(idp, fnum);
132 TALLOC_FREE(*pph);
133 return NT_STATUS_OK;
136 /***************************************************************
137 Oplock mapping code.
138 ***************************************************************/
140 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
142 if (create_flags & REQUEST_BATCH_OPLOCK) {
143 return SMB2_OPLOCK_LEVEL_BATCH;
144 } else if (create_flags & REQUEST_OPLOCK) {
145 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
148 /* create_flags doesn't do a level2 request. */
149 return SMB2_OPLOCK_LEVEL_NONE;
152 /***************************************************************
153 Small wrapper that allows SMB2 create to return a uint16_t fnum.
154 ***************************************************************/
156 struct cli_smb2_create_fnum_state {
157 struct cli_state *cli;
158 struct smb_create_returns cr;
159 uint16_t fnum;
160 struct tevent_req *subreq;
163 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
164 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
166 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
167 struct tevent_context *ev,
168 struct cli_state *cli,
169 const char *fname,
170 uint32_t create_flags,
171 uint32_t desired_access,
172 uint32_t file_attributes,
173 uint32_t share_access,
174 uint32_t create_disposition,
175 uint32_t create_options)
177 struct tevent_req *req, *subreq;
178 struct cli_smb2_create_fnum_state *state;
180 req = tevent_req_create(mem_ctx, &state,
181 struct cli_smb2_create_fnum_state);
182 if (req == NULL) {
183 return NULL;
185 state->cli = cli;
187 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
188 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
189 return tevent_req_post(req, ev);
192 if (cli->backup_intent) {
193 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
196 /* SMB2 is pickier about pathnames. Ensure it doesn't
197 start in a '\' */
198 if (*fname == '\\') {
199 fname++;
202 subreq = smb2cli_create_send(state, ev,
203 cli->conn,
204 cli->timeout,
205 cli->smb2.session,
206 cli->smb2.tcon,
207 fname,
208 flags_to_smb2_oplock(create_flags),
209 SMB2_IMPERSONATION_IMPERSONATION,
210 desired_access,
211 file_attributes,
212 share_access,
213 create_disposition,
214 create_options,
215 NULL);
216 if (tevent_req_nomem(subreq, req)) {
217 return tevent_req_post(req, ev);
219 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
221 state->subreq = subreq;
222 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
224 return req;
227 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
229 struct tevent_req *req = tevent_req_callback_data(
230 subreq, struct tevent_req);
231 struct cli_smb2_create_fnum_state *state = tevent_req_data(
232 req, struct cli_smb2_create_fnum_state);
233 struct smb2_hnd h;
234 NTSTATUS status;
236 status = smb2cli_create_recv(subreq, &h.fid_persistent,
237 &h.fid_volatile, &state->cr);
238 TALLOC_FREE(subreq);
239 if (tevent_req_nterror(req, status)) {
240 return;
243 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
244 if (tevent_req_nterror(req, status)) {
245 return;
247 tevent_req_done(req);
250 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
252 struct cli_smb2_create_fnum_state *state = tevent_req_data(
253 req, struct cli_smb2_create_fnum_state);
254 return tevent_req_cancel(state->subreq);
257 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
258 struct smb_create_returns *cr)
260 struct cli_smb2_create_fnum_state *state = tevent_req_data(
261 req, struct cli_smb2_create_fnum_state);
262 NTSTATUS status;
264 if (tevent_req_is_nterror(req, &status)) {
265 return status;
267 if (pfnum != NULL) {
268 *pfnum = state->fnum;
270 if (cr != NULL) {
271 *cr = state->cr;
273 return NT_STATUS_OK;
276 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
277 const char *fname,
278 uint32_t create_flags,
279 uint32_t desired_access,
280 uint32_t file_attributes,
281 uint32_t share_access,
282 uint32_t create_disposition,
283 uint32_t create_options,
284 uint16_t *pfid,
285 struct smb_create_returns *cr)
287 TALLOC_CTX *frame = talloc_stackframe();
288 struct tevent_context *ev;
289 struct tevent_req *req;
290 NTSTATUS status = NT_STATUS_NO_MEMORY;
292 if (smbXcli_conn_has_async_calls(cli->conn)) {
294 * Can't use sync call while an async call is in flight
296 status = NT_STATUS_INVALID_PARAMETER;
297 goto fail;
299 ev = samba_tevent_context_init(frame);
300 if (ev == NULL) {
301 goto fail;
303 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
304 desired_access, file_attributes,
305 share_access, create_disposition,
306 create_options);
307 if (req == NULL) {
308 goto fail;
310 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
311 goto fail;
313 status = cli_smb2_create_fnum_recv(req, pfid, cr);
314 fail:
315 TALLOC_FREE(frame);
316 return status;
319 /***************************************************************
320 Small wrapper that allows SMB2 close to use a uint16_t fnum.
321 Synchronous only.
322 ***************************************************************/
324 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
326 struct smb2_hnd *ph = NULL;
327 NTSTATUS status;
329 if (smbXcli_conn_has_async_calls(cli->conn)) {
331 * Can't use sync call while an async call is in flight
333 return NT_STATUS_INVALID_PARAMETER;
336 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
337 return NT_STATUS_INVALID_PARAMETER;
340 status = map_fnum_to_smb2_handle(cli,
341 fnum,
342 &ph);
343 if (!NT_STATUS_IS_OK(status)) {
344 return status;
347 status = smb2cli_close(cli->conn,
348 cli->timeout,
349 cli->smb2.session,
350 cli->smb2.tcon,
352 ph->fid_persistent,
353 ph->fid_volatile);
355 /* Delete the fnum -> handle mapping. */
356 if (NT_STATUS_IS_OK(status)) {
357 status = delete_smb2_handle_mapping(cli, &ph, fnum);
360 return status;
363 /***************************************************************
364 Small wrapper that allows SMB2 to create a directory
365 Synchronous only.
366 ***************************************************************/
368 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
370 NTSTATUS status;
371 uint16_t fnum;
373 if (smbXcli_conn_has_async_calls(cli->conn)) {
375 * Can't use sync call while an async call is in flight
377 return NT_STATUS_INVALID_PARAMETER;
380 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
381 return NT_STATUS_INVALID_PARAMETER;
384 status = cli_smb2_create_fnum(cli,
385 dname,
386 0, /* create_flags */
387 FILE_READ_ATTRIBUTES, /* desired_access */
388 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
389 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
390 FILE_CREATE, /* create_disposition */
391 FILE_DIRECTORY_FILE, /* create_options */
392 &fnum,
393 NULL);
395 if (!NT_STATUS_IS_OK(status)) {
396 return status;
398 return cli_smb2_close_fnum(cli, fnum);
401 /***************************************************************
402 Small wrapper that allows SMB2 to delete a directory
403 Synchronous only.
404 ***************************************************************/
406 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
408 NTSTATUS status;
409 uint16_t fnum;
411 if (smbXcli_conn_has_async_calls(cli->conn)) {
413 * Can't use sync call while an async call is in flight
415 return NT_STATUS_INVALID_PARAMETER;
418 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
419 return NT_STATUS_INVALID_PARAMETER;
422 status = cli_smb2_create_fnum(cli,
423 dname,
424 0, /* create_flags */
425 DELETE_ACCESS, /* desired_access */
426 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
427 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
428 FILE_OPEN, /* create_disposition */
429 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
430 &fnum,
431 NULL);
433 if (!NT_STATUS_IS_OK(status)) {
434 return status;
436 return cli_smb2_close_fnum(cli, fnum);
439 /***************************************************************
440 Small wrapper that allows SMB2 to unlink a pathname.
441 Synchronous only.
442 ***************************************************************/
444 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
446 NTSTATUS status;
447 uint16_t fnum;
449 if (smbXcli_conn_has_async_calls(cli->conn)) {
451 * Can't use sync call while an async call is in flight
453 return NT_STATUS_INVALID_PARAMETER;
456 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
457 return NT_STATUS_INVALID_PARAMETER;
460 status = cli_smb2_create_fnum(cli,
461 fname,
462 0, /* create_flags */
463 DELETE_ACCESS, /* desired_access */
464 FILE_ATTRIBUTE_NORMAL, /* file attributes */
465 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
466 FILE_OPEN, /* create_disposition */
467 FILE_DELETE_ON_CLOSE, /* create_options */
468 &fnum,
469 NULL);
471 if (!NT_STATUS_IS_OK(status)) {
472 return status;
474 return cli_smb2_close_fnum(cli, fnum);
477 /***************************************************************
478 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
479 ***************************************************************/
481 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
482 uint32_t dir_data_length,
483 struct file_info *finfo,
484 uint32_t *next_offset)
486 size_t namelen = 0;
487 size_t slen = 0;
488 size_t ret = 0;
490 if (dir_data_length < 4) {
491 return NT_STATUS_INFO_LENGTH_MISMATCH;
494 *next_offset = IVAL(dir_data, 0);
496 if (*next_offset > dir_data_length) {
497 return NT_STATUS_INFO_LENGTH_MISMATCH;
500 if (*next_offset != 0) {
501 /* Ensure we only read what in this record. */
502 dir_data_length = *next_offset;
505 if (dir_data_length < 105) {
506 return NT_STATUS_INFO_LENGTH_MISMATCH;
509 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
510 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
511 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
512 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
513 finfo->mode = CVAL(dir_data + 56, 0);
514 namelen = IVAL(dir_data + 60,0);
515 if (namelen > (dir_data_length - 104)) {
516 return NT_STATUS_INFO_LENGTH_MISMATCH;
518 slen = CVAL(dir_data + 68, 0);
519 if (slen > 24) {
520 return NT_STATUS_INFO_LENGTH_MISMATCH;
522 ret = pull_string_talloc(finfo,
523 dir_data,
524 FLAGS2_UNICODE_STRINGS,
525 &finfo->short_name,
526 dir_data + 70,
527 slen,
528 STR_UNICODE);
529 if (ret == (size_t)-1) {
530 /* Bad conversion. */
531 return NT_STATUS_INVALID_NETWORK_RESPONSE;
534 ret = pull_string_talloc(finfo,
535 dir_data,
536 FLAGS2_UNICODE_STRINGS,
537 &finfo->name,
538 dir_data + 104,
539 namelen,
540 STR_UNICODE);
541 if (ret == (size_t)-1) {
542 /* Bad conversion. */
543 return NT_STATUS_INVALID_NETWORK_RESPONSE;
545 return NT_STATUS_OK;
548 /*******************************************************************
549 Given a filename - get its directory name
550 ********************************************************************/
552 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
553 const char *dir,
554 char **parent,
555 const char **name)
557 char *p;
558 ptrdiff_t len;
560 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
562 if (p == NULL) {
563 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
564 return false;
566 if (name) {
567 *name = dir;
569 return true;
572 len = p-dir;
574 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
575 return false;
577 (*parent)[len] = '\0';
579 if (name) {
580 *name = p+1;
582 return true;
585 /***************************************************************
586 Wrapper that allows SMB2 to list a directory.
587 Synchronous only.
588 ***************************************************************/
590 NTSTATUS cli_smb2_list(struct cli_state *cli,
591 const char *pathname,
592 uint16_t attribute,
593 NTSTATUS (*fn)(const char *,
594 struct file_info *,
595 const char *,
596 void *),
597 void *state)
599 NTSTATUS status;
600 uint16_t fnum = 0xffff;
601 char *parent_dir = NULL;
602 const char *mask = NULL;
603 struct smb2_hnd *ph = NULL;
604 bool processed_file = false;
605 TALLOC_CTX *frame = talloc_stackframe();
606 TALLOC_CTX *subframe = NULL;
608 if (smbXcli_conn_has_async_calls(cli->conn)) {
610 * Can't use sync call while an async call is in flight
612 status = NT_STATUS_INVALID_PARAMETER;
613 goto fail;
616 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
617 status = NT_STATUS_INVALID_PARAMETER;
618 goto fail;
621 /* Get the directory name. */
622 if (!windows_parent_dirname(frame,
623 pathname,
624 &parent_dir,
625 &mask)) {
626 status = NT_STATUS_NO_MEMORY;
627 goto fail;
630 status = cli_smb2_create_fnum(cli,
631 parent_dir,
632 0, /* create_flags */
633 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
634 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
635 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
636 FILE_OPEN, /* create_disposition */
637 FILE_DIRECTORY_FILE, /* create_options */
638 &fnum,
639 NULL);
641 if (!NT_STATUS_IS_OK(status)) {
642 goto fail;
645 status = map_fnum_to_smb2_handle(cli,
646 fnum,
647 &ph);
648 if (!NT_STATUS_IS_OK(status)) {
649 goto fail;
652 do {
653 uint8_t *dir_data = NULL;
654 uint32_t dir_data_length = 0;
655 uint32_t next_offset = 0;
656 subframe = talloc_stackframe();
658 status = smb2cli_query_directory(cli->conn,
659 cli->timeout,
660 cli->smb2.session,
661 cli->smb2.tcon,
662 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
663 0, /* flags */
664 0, /* file_index */
665 ph->fid_persistent,
666 ph->fid_volatile,
667 mask,
668 0xffff,
669 subframe,
670 &dir_data,
671 &dir_data_length);
673 if (!NT_STATUS_IS_OK(status)) {
674 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
675 break;
677 goto fail;
680 do {
681 struct file_info *finfo = talloc_zero(subframe,
682 struct file_info);
684 if (finfo == NULL) {
685 status = NT_STATUS_NO_MEMORY;
686 goto fail;
689 status = parse_finfo_id_both_directory_info(dir_data,
690 dir_data_length,
691 finfo,
692 &next_offset);
694 if (!NT_STATUS_IS_OK(status)) {
695 goto fail;
698 if (dir_check_ftype((uint32_t)finfo->mode,
699 (uint32_t)attribute)) {
701 * Only process if attributes match.
702 * On SMB1 server does this, so on
703 * SMB2 we need to emulate in the
704 * client.
706 * https://bugzilla.samba.org/show_bug.cgi?id=10260
708 processed_file = true;
710 status = fn(cli->dfs_mountpoint,
711 finfo,
712 pathname,
713 state);
715 if (!NT_STATUS_IS_OK(status)) {
716 break;
720 TALLOC_FREE(finfo);
722 /* Move to next entry. */
723 if (next_offset) {
724 dir_data += next_offset;
725 dir_data_length -= next_offset;
727 } while (next_offset != 0);
729 TALLOC_FREE(subframe);
731 } while (NT_STATUS_IS_OK(status));
733 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
734 status = NT_STATUS_OK;
737 if (NT_STATUS_IS_OK(status) && !processed_file) {
739 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
740 * if no files match. Emulate this in the client.
742 status = NT_STATUS_NO_SUCH_FILE;
745 fail:
747 if (fnum != 0xffff) {
748 cli_smb2_close_fnum(cli, fnum);
750 TALLOC_FREE(subframe);
751 TALLOC_FREE(frame);
752 return status;
755 /***************************************************************
756 Wrapper that allows SMB2 to query a path info (basic level).
757 Synchronous only.
758 ***************************************************************/
760 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
761 const char *name,
762 SMB_STRUCT_STAT *sbuf,
763 uint32_t *attributes)
765 NTSTATUS status;
766 struct smb_create_returns cr;
767 uint16_t fnum = 0xffff;
768 size_t namelen = strlen(name);
770 if (smbXcli_conn_has_async_calls(cli->conn)) {
772 * Can't use sync call while an async call is in flight
774 return NT_STATUS_INVALID_PARAMETER;
777 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
778 return NT_STATUS_INVALID_PARAMETER;
781 /* SMB2 is pickier about pathnames. Ensure it doesn't
782 end in a '\' */
783 if (namelen > 0 && name[namelen-1] == '\\') {
784 char *modname = talloc_strdup(talloc_tos(), name);
785 modname[namelen-1] = '\0';
786 name = modname;
789 /* This is commonly used as a 'cd'. Try qpathinfo on
790 a directory handle first. */
792 status = cli_smb2_create_fnum(cli,
793 name,
794 0, /* create_flags */
795 FILE_READ_ATTRIBUTES, /* desired_access */
796 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
797 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
798 FILE_OPEN, /* create_disposition */
799 FILE_DIRECTORY_FILE, /* create_options */
800 &fnum,
801 &cr);
803 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
804 /* Maybe a file ? */
805 status = cli_smb2_create_fnum(cli,
806 name,
807 0, /* create_flags */
808 FILE_READ_ATTRIBUTES, /* desired_access */
809 0, /* file attributes */
810 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
811 FILE_OPEN, /* create_disposition */
812 0, /* create_options */
813 &fnum,
814 &cr);
817 if (!NT_STATUS_IS_OK(status)) {
818 return status;
821 cli_smb2_close_fnum(cli, fnum);
823 ZERO_STRUCTP(sbuf);
825 sbuf->st_ex_atime = nt_time_to_unix_timespec(&cr.last_access_time);
826 sbuf->st_ex_mtime = nt_time_to_unix_timespec(&cr.last_write_time);
827 sbuf->st_ex_ctime = nt_time_to_unix_timespec(&cr.change_time);
828 sbuf->st_ex_size = cr.end_of_file;
829 *attributes = cr.file_attributes;
831 return NT_STATUS_OK;
834 /***************************************************************
835 Helper function for pathname operations.
836 ***************************************************************/
838 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
839 const char *name,
840 uint32_t desired_access,
841 uint16_t *pfnum)
843 NTSTATUS status;
844 size_t namelen = strlen(name);
845 TALLOC_CTX *frame = talloc_stackframe();
847 /* SMB2 is pickier about pathnames. Ensure it doesn't
848 end in a '\' */
849 if (namelen > 0 && name[namelen-1] == '\\') {
850 char *modname = talloc_strdup(frame, name);
851 if (modname == NULL) {
852 status = NT_STATUS_NO_MEMORY;
853 goto fail;
855 modname[namelen-1] = '\0';
856 name = modname;
859 /* Try to open a file handle first. */
860 status = cli_smb2_create_fnum(cli,
861 name,
862 0, /* create_flags */
863 desired_access,
864 0, /* file attributes */
865 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
866 FILE_OPEN, /* create_disposition */
867 0, /* create_options */
868 pfnum,
869 NULL);
871 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
872 status = cli_smb2_create_fnum(cli,
873 name,
874 0, /* create_flags */
875 desired_access,
876 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
877 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
878 FILE_OPEN, /* create_disposition */
879 FILE_DIRECTORY_FILE, /* create_options */
880 pfnum,
881 NULL);
884 fail:
886 TALLOC_FREE(frame);
887 return status;
890 /***************************************************************
891 Wrapper that allows SMB2 to query a path info (ALTNAME level).
892 Synchronous only.
893 ***************************************************************/
895 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
896 const char *name,
897 fstring alt_name)
899 NTSTATUS status;
900 DATA_BLOB outbuf = data_blob_null;
901 uint16_t fnum = 0xffff;
902 struct smb2_hnd *ph = NULL;
903 uint32_t altnamelen = 0;
904 TALLOC_CTX *frame = talloc_stackframe();
906 if (smbXcli_conn_has_async_calls(cli->conn)) {
908 * Can't use sync call while an async call is in flight
910 status = NT_STATUS_INVALID_PARAMETER;
911 goto fail;
914 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
915 status = NT_STATUS_INVALID_PARAMETER;
916 goto fail;
919 status = get_fnum_from_path(cli,
920 name,
921 FILE_READ_ATTRIBUTES,
922 &fnum);
924 if (!NT_STATUS_IS_OK(status)) {
925 goto fail;
928 status = map_fnum_to_smb2_handle(cli,
929 fnum,
930 &ph);
931 if (!NT_STATUS_IS_OK(status)) {
932 goto fail;
935 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
936 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
938 status = smb2cli_query_info(cli->conn,
939 cli->timeout,
940 cli->smb2.session,
941 cli->smb2.tcon,
942 1, /* in_info_type */
943 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
944 0xFFFF, /* in_max_output_length */
945 NULL, /* in_input_buffer */
946 0, /* in_additional_info */
947 0, /* in_flags */
948 ph->fid_persistent,
949 ph->fid_volatile,
950 frame,
951 &outbuf);
953 if (!NT_STATUS_IS_OK(status)) {
954 goto fail;
957 /* Parse the reply. */
958 if (outbuf.length < 4) {
959 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
960 goto fail;
963 altnamelen = IVAL(outbuf.data, 0);
964 if (altnamelen > outbuf.length - 4) {
965 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
966 goto fail;
969 if (altnamelen > 0) {
970 size_t ret = 0;
971 char *short_name = NULL;
972 ret = pull_string_talloc(frame,
973 outbuf.data,
974 FLAGS2_UNICODE_STRINGS,
975 &short_name,
976 outbuf.data + 4,
977 altnamelen,
978 STR_UNICODE);
979 if (ret == (size_t)-1) {
980 /* Bad conversion. */
981 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
982 goto fail;
985 fstrcpy(alt_name, short_name);
986 } else {
987 alt_name[0] = '\0';
990 status = NT_STATUS_OK;
992 fail:
994 if (fnum != 0xffff) {
995 cli_smb2_close_fnum(cli, fnum);
997 TALLOC_FREE(frame);
998 return status;
1002 /***************************************************************
1003 Wrapper that allows SMB2 to query a fnum info (basic level).
1004 Synchronous only.
1005 ***************************************************************/
1007 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1008 uint16_t fnum,
1009 uint16_t *mode,
1010 off_t *size,
1011 struct timespec *create_time,
1012 struct timespec *access_time,
1013 struct timespec *write_time,
1014 struct timespec *change_time,
1015 SMB_INO_T *ino)
1017 NTSTATUS status;
1018 DATA_BLOB outbuf = data_blob_null;
1019 struct smb2_hnd *ph = NULL;
1020 TALLOC_CTX *frame = talloc_stackframe();
1022 if (smbXcli_conn_has_async_calls(cli->conn)) {
1024 * Can't use sync call while an async call is in flight
1026 status = NT_STATUS_INVALID_PARAMETER;
1027 goto fail;
1030 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1031 status = NT_STATUS_INVALID_PARAMETER;
1032 goto fail;
1035 status = map_fnum_to_smb2_handle(cli,
1036 fnum,
1037 &ph);
1038 if (!NT_STATUS_IS_OK(status)) {
1039 goto fail;
1042 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1043 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1045 status = smb2cli_query_info(cli->conn,
1046 cli->timeout,
1047 cli->smb2.session,
1048 cli->smb2.tcon,
1049 1, /* in_info_type */
1050 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1051 0xFFFF, /* in_max_output_length */
1052 NULL, /* in_input_buffer */
1053 0, /* in_additional_info */
1054 0, /* in_flags */
1055 ph->fid_persistent,
1056 ph->fid_volatile,
1057 frame,
1058 &outbuf);
1059 if (!NT_STATUS_IS_OK(status)) {
1060 goto fail;
1063 /* Parse the reply. */
1064 if (outbuf.length < 0x60) {
1065 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1066 goto fail;
1069 if (create_time) {
1070 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1072 if (access_time) {
1073 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1075 if (write_time) {
1076 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1078 if (change_time) {
1079 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1081 if (mode) {
1082 uint32_t attr = IVAL(outbuf.data, 0x20);
1083 *mode = (uint16_t)attr;
1085 if (size) {
1086 uint64_t file_size = BVAL(outbuf.data, 0x30);
1087 *size = (off_t)file_size;
1089 if (ino) {
1090 uint64_t file_index = BVAL(outbuf.data, 0x40);
1091 *ino = (SMB_INO_T)file_index;
1094 fail:
1096 TALLOC_FREE(frame);
1097 return status;
1100 /***************************************************************
1101 Wrapper that allows SMB2 to query an fnum.
1102 Implement on top of cli_smb2_qfileinfo_basic().
1103 Synchronous only.
1104 ***************************************************************/
1106 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1107 uint16_t fnum,
1108 uint16_t *attr,
1109 off_t *size,
1110 time_t *change_time,
1111 time_t *access_time,
1112 time_t *write_time)
1114 struct timespec access_time_ts;
1115 struct timespec write_time_ts;
1116 struct timespec change_time_ts;
1117 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1118 fnum,
1119 attr,
1120 size,
1121 NULL,
1122 &access_time_ts,
1123 &write_time_ts,
1124 &change_time_ts,
1125 NULL);
1127 if (!NT_STATUS_IS_OK(status)) {
1128 return status;
1131 if (change_time) {
1132 *change_time = change_time_ts.tv_sec;
1134 if (access_time) {
1135 *access_time = access_time_ts.tv_sec;
1137 if (write_time) {
1138 *write_time = write_time_ts.tv_sec;
1140 return NT_STATUS_OK;
1143 /***************************************************************
1144 Wrapper that allows SMB2 to get pathname attributes.
1145 Synchronous only.
1146 ***************************************************************/
1148 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1149 const char *name,
1150 uint16_t *attr,
1151 off_t *size,
1152 time_t *write_time)
1154 NTSTATUS status;
1155 uint16_t fnum = 0xffff;
1156 struct smb2_hnd *ph = NULL;
1157 TALLOC_CTX *frame = talloc_stackframe();
1159 if (smbXcli_conn_has_async_calls(cli->conn)) {
1161 * Can't use sync call while an async call is in flight
1163 status = NT_STATUS_INVALID_PARAMETER;
1164 goto fail;
1167 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1168 status = NT_STATUS_INVALID_PARAMETER;
1169 goto fail;
1172 status = get_fnum_from_path(cli,
1173 name,
1174 FILE_READ_ATTRIBUTES,
1175 &fnum);
1177 if (!NT_STATUS_IS_OK(status)) {
1178 goto fail;
1181 status = map_fnum_to_smb2_handle(cli,
1182 fnum,
1183 &ph);
1184 if (!NT_STATUS_IS_OK(status)) {
1185 goto fail;
1187 status = cli_smb2_getattrE(cli,
1188 fnum,
1189 attr,
1190 size,
1191 NULL,
1192 NULL,
1193 write_time);
1194 if (!NT_STATUS_IS_OK(status)) {
1195 goto fail;
1198 fail:
1200 if (fnum != 0xffff) {
1201 cli_smb2_close_fnum(cli, fnum);
1204 TALLOC_FREE(frame);
1205 return status;
1208 /***************************************************************
1209 Wrapper that allows SMB2 to query a pathname info (basic level).
1210 Implement on top of cli_smb2_qfileinfo_basic().
1211 Synchronous only.
1212 ***************************************************************/
1214 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1215 const char *name,
1216 struct timespec *create_time,
1217 struct timespec *access_time,
1218 struct timespec *write_time,
1219 struct timespec *change_time,
1220 off_t *size,
1221 uint16_t *mode,
1222 SMB_INO_T *ino)
1224 NTSTATUS status;
1225 struct smb2_hnd *ph = NULL;
1226 uint16_t fnum = 0xffff;
1227 TALLOC_CTX *frame = talloc_stackframe();
1229 if (smbXcli_conn_has_async_calls(cli->conn)) {
1231 * Can't use sync call while an async call is in flight
1233 status = NT_STATUS_INVALID_PARAMETER;
1234 goto fail;
1237 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1238 status = NT_STATUS_INVALID_PARAMETER;
1239 goto fail;
1242 status = get_fnum_from_path(cli,
1243 name,
1244 FILE_READ_ATTRIBUTES,
1245 &fnum);
1247 if (!NT_STATUS_IS_OK(status)) {
1248 goto fail;
1251 status = map_fnum_to_smb2_handle(cli,
1252 fnum,
1253 &ph);
1254 if (!NT_STATUS_IS_OK(status)) {
1255 goto fail;
1258 status = cli_smb2_qfileinfo_basic(cli,
1259 fnum,
1260 mode,
1261 size,
1262 create_time,
1263 access_time,
1264 write_time,
1265 change_time,
1266 ino);
1268 fail:
1270 if (fnum != 0xffff) {
1271 cli_smb2_close_fnum(cli, fnum);
1274 TALLOC_FREE(frame);
1275 return status;
1278 /***************************************************************
1279 Wrapper that allows SMB2 to query pathname streams.
1280 Synchronous only.
1281 ***************************************************************/
1283 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1284 const char *name,
1285 TALLOC_CTX *mem_ctx,
1286 unsigned int *pnum_streams,
1287 struct stream_struct **pstreams)
1289 NTSTATUS status;
1290 struct smb2_hnd *ph = NULL;
1291 uint16_t fnum = 0xffff;
1292 DATA_BLOB outbuf = data_blob_null;
1293 TALLOC_CTX *frame = talloc_stackframe();
1295 if (smbXcli_conn_has_async_calls(cli->conn)) {
1297 * Can't use sync call while an async call is in flight
1299 status = NT_STATUS_INVALID_PARAMETER;
1300 goto fail;
1303 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1304 status = NT_STATUS_INVALID_PARAMETER;
1305 goto fail;
1308 status = get_fnum_from_path(cli,
1309 name,
1310 FILE_READ_ATTRIBUTES,
1311 &fnum);
1313 if (!NT_STATUS_IS_OK(status)) {
1314 goto fail;
1317 status = map_fnum_to_smb2_handle(cli,
1318 fnum,
1319 &ph);
1320 if (!NT_STATUS_IS_OK(status)) {
1321 goto fail;
1324 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1325 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1327 status = smb2cli_query_info(cli->conn,
1328 cli->timeout,
1329 cli->smb2.session,
1330 cli->smb2.tcon,
1331 1, /* in_info_type */
1332 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1333 0xFFFF, /* in_max_output_length */
1334 NULL, /* in_input_buffer */
1335 0, /* in_additional_info */
1336 0, /* in_flags */
1337 ph->fid_persistent,
1338 ph->fid_volatile,
1339 frame,
1340 &outbuf);
1342 if (!NT_STATUS_IS_OK(status)) {
1343 goto fail;
1346 /* Parse the reply. */
1347 if (!parse_streams_blob(mem_ctx,
1348 outbuf.data,
1349 outbuf.length,
1350 pnum_streams,
1351 pstreams)) {
1352 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1353 goto fail;
1356 fail:
1358 if (fnum != 0xffff) {
1359 cli_smb2_close_fnum(cli, fnum);
1362 TALLOC_FREE(frame);
1363 return status;
1366 /***************************************************************
1367 Wrapper that allows SMB2 to set pathname attributes.
1368 Synchronous only.
1369 ***************************************************************/
1371 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1372 const char *name,
1373 uint16_t attr,
1374 time_t mtime)
1376 NTSTATUS status;
1377 uint16_t fnum = 0xffff;
1378 struct smb2_hnd *ph = NULL;
1379 uint8_t inbuf_store[40];
1380 DATA_BLOB inbuf = data_blob_null;
1381 TALLOC_CTX *frame = talloc_stackframe();
1383 if (smbXcli_conn_has_async_calls(cli->conn)) {
1385 * Can't use sync call while an async call is in flight
1387 status = NT_STATUS_INVALID_PARAMETER;
1388 goto fail;
1391 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1392 status = NT_STATUS_INVALID_PARAMETER;
1393 goto fail;
1396 status = get_fnum_from_path(cli,
1397 name,
1398 FILE_WRITE_ATTRIBUTES,
1399 &fnum);
1401 if (!NT_STATUS_IS_OK(status)) {
1402 goto fail;
1405 status = map_fnum_to_smb2_handle(cli,
1406 fnum,
1407 &ph);
1408 if (!NT_STATUS_IS_OK(status)) {
1409 goto fail;
1412 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1413 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1415 inbuf.data = inbuf_store;
1416 inbuf.length = sizeof(inbuf_store);
1417 data_blob_clear(&inbuf);
1419 SSVAL(inbuf.data, 32, attr);
1420 if (mtime != 0) {
1421 put_long_date((char *)inbuf.data + 16,mtime);
1423 /* Set all the other times to -1. */
1424 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1425 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1426 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1428 status = smb2cli_set_info(cli->conn,
1429 cli->timeout,
1430 cli->smb2.session,
1431 cli->smb2.tcon,
1432 1, /* in_info_type */
1433 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1434 &inbuf, /* in_input_buffer */
1435 0, /* in_additional_info */
1436 ph->fid_persistent,
1437 ph->fid_volatile);
1438 fail:
1440 if (fnum != 0xffff) {
1441 cli_smb2_close_fnum(cli, fnum);
1444 TALLOC_FREE(frame);
1445 return status;
1448 /***************************************************************
1449 Wrapper that allows SMB2 to set file handle times.
1450 Synchronous only.
1451 ***************************************************************/
1453 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1454 uint16_t fnum,
1455 time_t change_time,
1456 time_t access_time,
1457 time_t write_time)
1459 NTSTATUS status;
1460 struct smb2_hnd *ph = NULL;
1461 uint8_t inbuf_store[40];
1462 DATA_BLOB inbuf = data_blob_null;
1464 if (smbXcli_conn_has_async_calls(cli->conn)) {
1466 * Can't use sync call while an async call is in flight
1468 return NT_STATUS_INVALID_PARAMETER;
1471 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1472 return NT_STATUS_INVALID_PARAMETER;
1475 status = map_fnum_to_smb2_handle(cli,
1476 fnum,
1477 &ph);
1478 if (!NT_STATUS_IS_OK(status)) {
1479 return status;
1482 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1483 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1485 inbuf.data = inbuf_store;
1486 inbuf.length = sizeof(inbuf_store);
1487 data_blob_clear(&inbuf);
1489 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1490 if (change_time != 0) {
1491 put_long_date((char *)inbuf.data + 24, change_time);
1493 if (access_time != 0) {
1494 put_long_date((char *)inbuf.data + 8, access_time);
1496 if (write_time != 0) {
1497 put_long_date((char *)inbuf.data + 16, write_time);
1500 return smb2cli_set_info(cli->conn,
1501 cli->timeout,
1502 cli->smb2.session,
1503 cli->smb2.tcon,
1504 1, /* in_info_type */
1505 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1506 &inbuf, /* in_input_buffer */
1507 0, /* in_additional_info */
1508 ph->fid_persistent,
1509 ph->fid_volatile);
1512 /***************************************************************
1513 Wrapper that allows SMB2 to query disk attributes (size).
1514 Synchronous only.
1515 ***************************************************************/
1517 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, uint64_t *bsize, uint64_t *total, uint64_t *avail)
1519 NTSTATUS status;
1520 uint16_t fnum = 0xffff;
1521 DATA_BLOB outbuf = data_blob_null;
1522 struct smb2_hnd *ph = NULL;
1523 uint32_t sectors_per_unit = 0;
1524 uint32_t bytes_per_sector = 0;
1525 uint64_t total_size = 0;
1526 uint64_t size_free = 0;
1527 TALLOC_CTX *frame = talloc_stackframe();
1529 if (smbXcli_conn_has_async_calls(cli->conn)) {
1531 * Can't use sync call while an async call is in flight
1533 status = NT_STATUS_INVALID_PARAMETER;
1534 goto fail;
1537 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1538 status = NT_STATUS_INVALID_PARAMETER;
1539 goto fail;
1542 /* First open the top level directory. */
1543 status = cli_smb2_create_fnum(cli,
1545 0, /* create_flags */
1546 FILE_READ_ATTRIBUTES, /* desired_access */
1547 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1548 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1549 FILE_OPEN, /* create_disposition */
1550 FILE_DIRECTORY_FILE, /* create_options */
1551 &fnum,
1552 NULL);
1554 if (!NT_STATUS_IS_OK(status)) {
1555 goto fail;
1558 status = map_fnum_to_smb2_handle(cli,
1559 fnum,
1560 &ph);
1561 if (!NT_STATUS_IS_OK(status)) {
1562 goto fail;
1565 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1566 level 3 (SMB_FS_SIZE_INFORMATION). */
1568 status = smb2cli_query_info(cli->conn,
1569 cli->timeout,
1570 cli->smb2.session,
1571 cli->smb2.tcon,
1572 2, /* in_info_type */
1573 3, /* in_file_info_class */
1574 0xFFFF, /* in_max_output_length */
1575 NULL, /* in_input_buffer */
1576 0, /* in_additional_info */
1577 0, /* in_flags */
1578 ph->fid_persistent,
1579 ph->fid_volatile,
1580 frame,
1581 &outbuf);
1582 if (!NT_STATUS_IS_OK(status)) {
1583 goto fail;
1586 /* Parse the reply. */
1587 if (outbuf.length != 24) {
1588 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1589 goto fail;
1592 total_size = BVAL(outbuf.data, 0);
1593 size_free = BVAL(outbuf.data, 8);
1594 sectors_per_unit = IVAL(outbuf.data, 16);
1595 bytes_per_sector = IVAL(outbuf.data, 20);
1597 if (bsize) {
1598 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1600 if (total) {
1601 *total = total_size;
1603 if (avail) {
1604 *avail = size_free;
1607 status = NT_STATUS_OK;
1609 fail:
1611 if (fnum != 0xffff) {
1612 cli_smb2_close_fnum(cli, fnum);
1615 TALLOC_FREE(frame);
1616 return status;
1619 /***************************************************************
1620 Wrapper that allows SMB2 to query a security descriptor.
1621 Synchronous only.
1622 ***************************************************************/
1624 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1625 uint16_t fnum,
1626 uint32_t sec_info,
1627 TALLOC_CTX *mem_ctx,
1628 struct security_descriptor **ppsd)
1630 NTSTATUS status;
1631 DATA_BLOB outbuf = data_blob_null;
1632 struct smb2_hnd *ph = NULL;
1633 struct security_descriptor *lsd = NULL;
1634 TALLOC_CTX *frame = talloc_stackframe();
1636 if (smbXcli_conn_has_async_calls(cli->conn)) {
1638 * Can't use sync call while an async call is in flight
1640 status = NT_STATUS_INVALID_PARAMETER;
1641 goto fail;
1644 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1645 status = NT_STATUS_INVALID_PARAMETER;
1646 goto fail;
1649 status = map_fnum_to_smb2_handle(cli,
1650 fnum,
1651 &ph);
1652 if (!NT_STATUS_IS_OK(status)) {
1653 goto fail;
1656 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1658 status = smb2cli_query_info(cli->conn,
1659 cli->timeout,
1660 cli->smb2.session,
1661 cli->smb2.tcon,
1662 3, /* in_info_type */
1663 0, /* in_file_info_class */
1664 0xFFFF, /* in_max_output_length */
1665 NULL, /* in_input_buffer */
1666 sec_info, /* in_additional_info */
1667 0, /* in_flags */
1668 ph->fid_persistent,
1669 ph->fid_volatile,
1670 frame,
1671 &outbuf);
1673 if (!NT_STATUS_IS_OK(status)) {
1674 goto fail;
1677 /* Parse the reply. */
1678 status = unmarshall_sec_desc(mem_ctx,
1679 outbuf.data,
1680 outbuf.length,
1681 &lsd);
1683 if (!NT_STATUS_IS_OK(status)) {
1684 goto fail;
1687 if (ppsd != NULL) {
1688 *ppsd = lsd;
1689 } else {
1690 TALLOC_FREE(lsd);
1693 fail:
1695 TALLOC_FREE(frame);
1696 return status;
1699 /***************************************************************
1700 Wrapper that allows SMB2 to set a security descriptor.
1701 Synchronous only.
1702 ***************************************************************/
1704 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1705 uint16_t fnum,
1706 uint32_t sec_info,
1707 const struct security_descriptor *sd)
1709 NTSTATUS status;
1710 DATA_BLOB inbuf = data_blob_null;
1711 struct smb2_hnd *ph = NULL;
1712 TALLOC_CTX *frame = talloc_stackframe();
1714 if (smbXcli_conn_has_async_calls(cli->conn)) {
1716 * Can't use sync call while an async call is in flight
1718 status = NT_STATUS_INVALID_PARAMETER;
1719 goto fail;
1722 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1723 status = NT_STATUS_INVALID_PARAMETER;
1724 goto fail;
1727 status = map_fnum_to_smb2_handle(cli,
1728 fnum,
1729 &ph);
1730 if (!NT_STATUS_IS_OK(status)) {
1731 goto fail;
1734 status = marshall_sec_desc(frame,
1736 &inbuf.data,
1737 &inbuf.length);
1739 if (!NT_STATUS_IS_OK(status)) {
1740 goto fail;
1743 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1745 status = smb2cli_set_info(cli->conn,
1746 cli->timeout,
1747 cli->smb2.session,
1748 cli->smb2.tcon,
1749 3, /* in_info_type */
1750 0, /* in_file_info_class */
1751 &inbuf, /* in_input_buffer */
1752 sec_info, /* in_additional_info */
1753 ph->fid_persistent,
1754 ph->fid_volatile);
1756 fail:
1758 TALLOC_FREE(frame);
1759 return status;
1762 /***************************************************************
1763 Wrapper that allows SMB2 to rename a file.
1764 Synchronous only.
1765 ***************************************************************/
1767 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1768 const char *fname_src,
1769 const char *fname_dst)
1771 NTSTATUS status;
1772 DATA_BLOB inbuf = data_blob_null;
1773 uint16_t fnum = 0xffff;
1774 struct smb2_hnd *ph = NULL;
1775 smb_ucs2_t *converted_str = NULL;
1776 size_t converted_size_bytes = 0;
1777 size_t namelen = 0;
1778 TALLOC_CTX *frame = talloc_stackframe();
1780 if (smbXcli_conn_has_async_calls(cli->conn)) {
1782 * Can't use sync call while an async call is in flight
1784 status = NT_STATUS_INVALID_PARAMETER;
1785 goto fail;
1788 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1789 status = NT_STATUS_INVALID_PARAMETER;
1790 goto fail;
1793 status = get_fnum_from_path(cli,
1794 fname_src,
1795 DELETE_ACCESS,
1796 &fnum);
1798 if (!NT_STATUS_IS_OK(status)) {
1799 goto fail;
1802 status = map_fnum_to_smb2_handle(cli,
1803 fnum,
1804 &ph);
1805 if (!NT_STATUS_IS_OK(status)) {
1806 goto fail;
1809 /* SMB2 is pickier about pathnames. Ensure it doesn't
1810 start in a '\' */
1811 if (*fname_dst == '\\') {
1812 fname_dst++;
1815 /* SMB2 is pickier about pathnames. Ensure it doesn't
1816 end in a '\' */
1817 namelen = strlen(fname_dst);
1818 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
1819 char *modname = talloc_strdup(frame, fname_dst);
1820 modname[namelen-1] = '\0';
1821 fname_dst = modname;
1824 if (!push_ucs2_talloc(frame,
1825 &converted_str,
1826 fname_dst,
1827 &converted_size_bytes)) {
1828 status = NT_STATUS_INVALID_PARAMETER;
1829 goto fail;
1832 /* W2K8 insists the dest name is not null
1833 terminated. Remove the last 2 zero bytes
1834 and reduce the name length. */
1836 if (converted_size_bytes < 2) {
1837 status = NT_STATUS_INVALID_PARAMETER;
1838 goto fail;
1840 converted_size_bytes -= 2;
1842 inbuf = data_blob_talloc_zero(frame,
1843 20 + converted_size_bytes);
1844 if (inbuf.data == NULL) {
1845 status = NT_STATUS_NO_MEMORY;
1846 goto fail;
1849 SIVAL(inbuf.data, 16, converted_size_bytes);
1850 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
1852 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1853 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1855 status = smb2cli_set_info(cli->conn,
1856 cli->timeout,
1857 cli->smb2.session,
1858 cli->smb2.tcon,
1859 1, /* in_info_type */
1860 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
1861 &inbuf, /* in_input_buffer */
1862 0, /* in_additional_info */
1863 ph->fid_persistent,
1864 ph->fid_volatile);
1866 fail:
1868 if (fnum != 0xffff) {
1869 cli_smb2_close_fnum(cli, fnum);
1872 TALLOC_FREE(frame);
1873 return status;
1876 /***************************************************************
1877 Wrapper that allows SMB2 to set an EA on a fnum.
1878 Synchronous only.
1879 ***************************************************************/
1881 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
1882 uint16_t fnum,
1883 const char *ea_name,
1884 const char *ea_val,
1885 size_t ea_len)
1887 NTSTATUS status;
1888 DATA_BLOB inbuf = data_blob_null;
1889 size_t bloblen = 0;
1890 char *ea_name_ascii = NULL;
1891 size_t namelen = 0;
1892 struct smb2_hnd *ph = NULL;
1893 TALLOC_CTX *frame = talloc_stackframe();
1895 if (smbXcli_conn_has_async_calls(cli->conn)) {
1897 * Can't use sync call while an async call is in flight
1899 status = NT_STATUS_INVALID_PARAMETER;
1900 goto fail;
1903 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1904 status = NT_STATUS_INVALID_PARAMETER;
1905 goto fail;
1908 status = map_fnum_to_smb2_handle(cli,
1909 fnum,
1910 &ph);
1911 if (!NT_STATUS_IS_OK(status)) {
1912 goto fail;
1915 /* Marshall the SMB2 EA data. */
1916 if (ea_len > 0xFFFF) {
1917 status = NT_STATUS_INVALID_PARAMETER;
1918 goto fail;
1921 if (!push_ascii_talloc(frame,
1922 &ea_name_ascii,
1923 ea_name,
1924 &namelen)) {
1925 status = NT_STATUS_INVALID_PARAMETER;
1926 goto fail;
1929 if (namelen < 2 || namelen > 0xFF) {
1930 status = NT_STATUS_INVALID_PARAMETER;
1931 goto fail;
1934 bloblen = 8 + ea_len + namelen;
1935 /* Round up to a 4 byte boundary. */
1936 bloblen = ((bloblen + 3)&~3);
1938 inbuf = data_blob_talloc_zero(frame, bloblen);
1939 if (inbuf.data == NULL) {
1940 status = NT_STATUS_NO_MEMORY;
1941 goto fail;
1943 /* namelen doesn't include the NULL byte. */
1944 SCVAL(inbuf.data, 5, namelen - 1);
1945 SSVAL(inbuf.data, 6, ea_len);
1946 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
1947 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
1949 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1950 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1952 status = smb2cli_set_info(cli->conn,
1953 cli->timeout,
1954 cli->smb2.session,
1955 cli->smb2.tcon,
1956 1, /* in_info_type */
1957 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
1958 &inbuf, /* in_input_buffer */
1959 0, /* in_additional_info */
1960 ph->fid_persistent,
1961 ph->fid_volatile);
1963 fail:
1965 TALLOC_FREE(frame);
1966 return status;
1969 /***************************************************************
1970 Wrapper that allows SMB2 to set an EA on a pathname.
1971 Synchronous only.
1972 ***************************************************************/
1974 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
1975 const char *name,
1976 const char *ea_name,
1977 const char *ea_val,
1978 size_t ea_len)
1980 NTSTATUS status;
1981 uint16_t fnum = 0xffff;
1983 if (smbXcli_conn_has_async_calls(cli->conn)) {
1985 * Can't use sync call while an async call is in flight
1987 status = NT_STATUS_INVALID_PARAMETER;
1988 goto fail;
1991 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1992 status = NT_STATUS_INVALID_PARAMETER;
1993 goto fail;
1996 status = get_fnum_from_path(cli,
1997 name,
1998 FILE_WRITE_EA,
1999 &fnum);
2001 if (!NT_STATUS_IS_OK(status)) {
2002 goto fail;
2005 status = cli_set_ea_fnum(cli,
2006 fnum,
2007 ea_name,
2008 ea_val,
2009 ea_len);
2010 if (!NT_STATUS_IS_OK(status)) {
2011 goto fail;
2014 fail:
2016 if (fnum != 0xffff) {
2017 cli_smb2_close_fnum(cli, fnum);
2020 return status;
2023 /***************************************************************
2024 Wrapper that allows SMB2 to get an EA list on a pathname.
2025 Synchronous only.
2026 ***************************************************************/
2028 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2029 const char *name,
2030 TALLOC_CTX *ctx,
2031 size_t *pnum_eas,
2032 struct ea_struct **pea_array)
2034 NTSTATUS status;
2035 uint16_t fnum = 0xffff;
2036 DATA_BLOB outbuf = data_blob_null;
2037 struct smb2_hnd *ph = NULL;
2038 struct ea_list *ea_list = NULL;
2039 struct ea_list *eal = NULL;
2040 size_t ea_count = 0;
2041 TALLOC_CTX *frame = talloc_stackframe();
2043 *pnum_eas = 0;
2044 *pea_array = NULL;
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_READ_EA,
2062 &fnum);
2064 if (!NT_STATUS_IS_OK(status)) {
2065 goto fail;
2068 status = map_fnum_to_smb2_handle(cli,
2069 fnum,
2070 &ph);
2071 if (!NT_STATUS_IS_OK(status)) {
2072 goto fail;
2075 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2076 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2078 status = smb2cli_query_info(cli->conn,
2079 cli->timeout,
2080 cli->smb2.session,
2081 cli->smb2.tcon,
2082 1, /* in_info_type */
2083 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2084 0xFFFF, /* in_max_output_length */
2085 NULL, /* in_input_buffer */
2086 0, /* in_additional_info */
2087 0, /* in_flags */
2088 ph->fid_persistent,
2089 ph->fid_volatile,
2090 frame,
2091 &outbuf);
2093 if (!NT_STATUS_IS_OK(status)) {
2094 goto fail;
2097 /* Parse the reply. */
2098 ea_list = read_nttrans_ea_list(ctx,
2099 (const char *)outbuf.data,
2100 outbuf.length);
2101 if (ea_list == NULL) {
2102 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2103 goto fail;
2106 /* Convert to an array. */
2107 for (eal = ea_list; eal; eal = eal->next) {
2108 ea_count++;
2111 if (ea_count) {
2112 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2113 if (*pea_array == NULL) {
2114 status = NT_STATUS_NO_MEMORY;
2115 goto fail;
2117 ea_count = 0;
2118 for (eal = ea_list; eal; eal = eal->next) {
2119 (*pea_array)[ea_count++] = ea_list->ea;
2121 *pnum_eas = ea_count;
2124 fail:
2126 if (fnum != 0xffff) {
2127 cli_smb2_close_fnum(cli, fnum);
2130 TALLOC_FREE(frame);
2131 return status;
2134 struct cli_smb2_read_state {
2135 struct tevent_context *ev;
2136 struct cli_state *cli;
2137 struct smb2_hnd *ph;
2138 uint64_t start_offset;
2139 uint32_t size;
2140 uint32_t received;
2141 uint8_t *buf;
2144 static void cli_smb2_read_done(struct tevent_req *subreq);
2146 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2147 struct tevent_context *ev,
2148 struct cli_state *cli,
2149 uint16_t fnum,
2150 off_t offset,
2151 size_t size)
2153 NTSTATUS status;
2154 struct tevent_req *req, *subreq;
2155 struct cli_smb2_read_state *state;
2157 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2158 if (req == NULL) {
2159 return NULL;
2161 state->ev = ev;
2162 state->cli = cli;
2163 state->start_offset = (uint64_t)offset;
2164 state->size = (uint32_t)size;
2165 state->received = 0;
2166 state->buf = NULL;
2168 status = map_fnum_to_smb2_handle(cli,
2169 fnum,
2170 &state->ph);
2171 if (tevent_req_nterror(req, status)) {
2172 return tevent_req_post(req, ev);
2175 subreq = smb2cli_read_send(state,
2176 state->ev,
2177 state->cli->conn,
2178 state->cli->timeout,
2179 state->cli->smb2.session,
2180 state->cli->smb2.tcon,
2181 state->size,
2182 state->start_offset,
2183 state->ph->fid_persistent,
2184 state->ph->fid_volatile,
2185 0, /* minimum_count */
2186 0); /* remaining_bytes */
2188 if (tevent_req_nomem(subreq, req)) {
2189 return tevent_req_post(req, ev);
2191 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2192 return req;
2195 static void cli_smb2_read_done(struct tevent_req *subreq)
2197 struct tevent_req *req = tevent_req_callback_data(
2198 subreq, struct tevent_req);
2199 struct cli_smb2_read_state *state = tevent_req_data(
2200 req, struct cli_smb2_read_state);
2201 NTSTATUS status;
2203 status = smb2cli_read_recv(subreq, state,
2204 &state->buf, &state->received);
2205 if (tevent_req_nterror(req, status)) {
2206 return;
2209 if (state->received > state->size) {
2210 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2211 return;
2214 tevent_req_done(req);
2217 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2218 ssize_t *received,
2219 uint8_t **rcvbuf)
2221 NTSTATUS status;
2222 struct cli_smb2_read_state *state = tevent_req_data(
2223 req, struct cli_smb2_read_state);
2225 if (tevent_req_is_nterror(req, &status)) {
2226 return status;
2229 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2230 * better make sure that you copy it away before you talloc_free(req).
2231 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2233 *received = (ssize_t)state->received;
2234 *rcvbuf = state->buf;
2235 return NT_STATUS_OK;
2238 struct cli_smb2_write_state {
2239 struct tevent_context *ev;
2240 struct cli_state *cli;
2241 struct smb2_hnd *ph;
2242 uint32_t flags;
2243 const uint8_t *buf;
2244 uint64_t offset;
2245 uint32_t size;
2246 uint32_t written;
2249 static void cli_smb2_write_written(struct tevent_req *req);
2251 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2252 struct tevent_context *ev,
2253 struct cli_state *cli,
2254 uint16_t fnum,
2255 uint16_t mode,
2256 const uint8_t *buf,
2257 off_t offset,
2258 size_t size)
2260 NTSTATUS status;
2261 struct tevent_req *req, *subreq = NULL;
2262 struct cli_smb2_write_state *state = NULL;
2264 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2265 if (req == NULL) {
2266 return NULL;
2268 state->ev = ev;
2269 state->cli = cli;
2270 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2271 state->flags = (uint32_t)mode;
2272 state->buf = buf;
2273 state->offset = (uint64_t)offset;
2274 state->size = (uint32_t)size;
2275 state->written = 0;
2277 status = map_fnum_to_smb2_handle(cli,
2278 fnum,
2279 &state->ph);
2280 if (tevent_req_nterror(req, status)) {
2281 return tevent_req_post(req, ev);
2284 subreq = smb2cli_write_send(state,
2285 state->ev,
2286 state->cli->conn,
2287 state->cli->timeout,
2288 state->cli->smb2.session,
2289 state->cli->smb2.tcon,
2290 state->size,
2291 state->offset,
2292 state->ph->fid_persistent,
2293 state->ph->fid_volatile,
2294 0, /* remaining_bytes */
2295 state->flags, /* flags */
2296 state->buf);
2298 if (tevent_req_nomem(subreq, req)) {
2299 return tevent_req_post(req, ev);
2301 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2302 return req;
2305 static void cli_smb2_write_written(struct tevent_req *subreq)
2307 struct tevent_req *req = tevent_req_callback_data(
2308 subreq, struct tevent_req);
2309 struct cli_smb2_write_state *state = tevent_req_data(
2310 req, struct cli_smb2_write_state);
2311 NTSTATUS status;
2312 uint32_t written;
2314 status = smb2cli_write_recv(subreq, &written);
2315 TALLOC_FREE(subreq);
2316 if (tevent_req_nterror(req, status)) {
2317 return;
2320 state->written = written;
2322 tevent_req_done(req);
2325 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2326 size_t *pwritten)
2328 struct cli_smb2_write_state *state = tevent_req_data(
2329 req, struct cli_smb2_write_state);
2330 NTSTATUS status;
2332 if (tevent_req_is_nterror(req, &status)) {
2333 tevent_req_received(req);
2334 return status;
2337 if (pwritten != NULL) {
2338 *pwritten = (size_t)state->written;
2340 tevent_req_received(req);
2341 return NT_STATUS_OK;
2344 /***************************************************************
2345 Wrapper that allows SMB2 async write using an fnum.
2346 This is mostly cut-and-paste from Volker's code inside
2347 source3/libsmb/clireadwrite.c, adapted for SMB2.
2349 Done this way so I can reuse all the logic inside cli_push()
2350 for free :-).
2351 ***************************************************************/
2353 struct cli_smb2_writeall_state {
2354 struct tevent_context *ev;
2355 struct cli_state *cli;
2356 struct smb2_hnd *ph;
2357 uint32_t flags;
2358 const uint8_t *buf;
2359 uint64_t offset;
2360 uint32_t size;
2361 uint32_t written;
2364 static void cli_smb2_writeall_written(struct tevent_req *req);
2366 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2367 struct tevent_context *ev,
2368 struct cli_state *cli,
2369 uint16_t fnum,
2370 uint16_t mode,
2371 const uint8_t *buf,
2372 off_t offset,
2373 size_t size)
2375 NTSTATUS status;
2376 struct tevent_req *req, *subreq = NULL;
2377 struct cli_smb2_writeall_state *state = NULL;
2378 uint32_t to_write;
2379 uint32_t max_size;
2380 bool ok;
2382 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2383 if (req == NULL) {
2384 return NULL;
2386 state->ev = ev;
2387 state->cli = cli;
2388 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2389 state->flags = (uint32_t)mode;
2390 state->buf = buf;
2391 state->offset = (uint64_t)offset;
2392 state->size = (uint32_t)size;
2393 state->written = 0;
2395 status = map_fnum_to_smb2_handle(cli,
2396 fnum,
2397 &state->ph);
2398 if (tevent_req_nterror(req, status)) {
2399 return tevent_req_post(req, ev);
2402 to_write = state->size;
2403 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2404 to_write = MIN(max_size, to_write);
2405 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2406 if (ok) {
2407 to_write = MIN(max_size, to_write);
2410 subreq = smb2cli_write_send(state,
2411 state->ev,
2412 state->cli->conn,
2413 state->cli->timeout,
2414 state->cli->smb2.session,
2415 state->cli->smb2.tcon,
2416 to_write,
2417 state->offset,
2418 state->ph->fid_persistent,
2419 state->ph->fid_volatile,
2420 0, /* remaining_bytes */
2421 state->flags, /* flags */
2422 state->buf + state->written);
2424 if (tevent_req_nomem(subreq, req)) {
2425 return tevent_req_post(req, ev);
2427 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2428 return req;
2431 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2433 struct tevent_req *req = tevent_req_callback_data(
2434 subreq, struct tevent_req);
2435 struct cli_smb2_writeall_state *state = tevent_req_data(
2436 req, struct cli_smb2_writeall_state);
2437 NTSTATUS status;
2438 uint32_t written, to_write;
2439 uint32_t max_size;
2440 bool ok;
2442 status = smb2cli_write_recv(subreq, &written);
2443 TALLOC_FREE(subreq);
2444 if (tevent_req_nterror(req, status)) {
2445 return;
2448 state->written += written;
2450 if (state->written > state->size) {
2451 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2452 return;
2455 to_write = state->size - state->written;
2457 if (to_write == 0) {
2458 tevent_req_done(req);
2459 return;
2462 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2463 to_write = MIN(max_size, to_write);
2464 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2465 if (ok) {
2466 to_write = MIN(max_size, to_write);
2469 subreq = smb2cli_write_send(state,
2470 state->ev,
2471 state->cli->conn,
2472 state->cli->timeout,
2473 state->cli->smb2.session,
2474 state->cli->smb2.tcon,
2475 to_write,
2476 state->offset + state->written,
2477 state->ph->fid_persistent,
2478 state->ph->fid_volatile,
2479 0, /* remaining_bytes */
2480 state->flags, /* flags */
2481 state->buf + state->written);
2483 if (tevent_req_nomem(subreq, req)) {
2484 return;
2486 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2489 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
2490 size_t *pwritten)
2492 struct cli_smb2_writeall_state *state = tevent_req_data(
2493 req, struct cli_smb2_writeall_state);
2494 NTSTATUS status;
2496 if (tevent_req_is_nterror(req, &status)) {
2497 return status;
2499 if (pwritten != NULL) {
2500 *pwritten = (size_t)state->written;
2502 return NT_STATUS_OK;