libsmb: Make cli_smb2_create_fnum async
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blob6c240386742ab0969c296b97d358b2c2200a2e91
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;
162 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
164 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
165 struct tevent_context *ev,
166 struct cli_state *cli,
167 const char *fname,
168 uint32_t create_flags,
169 uint32_t desired_access,
170 uint32_t file_attributes,
171 uint32_t share_access,
172 uint32_t create_disposition,
173 uint32_t create_options)
175 struct tevent_req *req, *subreq;
176 struct cli_smb2_create_fnum_state *state;
178 req = tevent_req_create(mem_ctx, &state,
179 struct cli_smb2_create_fnum_state);
180 if (req == NULL) {
181 return NULL;
183 state->cli = cli;
185 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
186 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
187 return tevent_req_post(req, ev);
190 if (cli->backup_intent) {
191 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
194 /* SMB2 is pickier about pathnames. Ensure it doesn't
195 start in a '\' */
196 if (*fname == '\\') {
197 fname++;
200 subreq = smb2cli_create_send(state, ev,
201 cli->conn,
202 cli->timeout,
203 cli->smb2.session,
204 cli->smb2.tcon,
205 fname,
206 flags_to_smb2_oplock(create_flags),
207 SMB2_IMPERSONATION_IMPERSONATION,
208 desired_access,
209 file_attributes,
210 share_access,
211 create_disposition,
212 create_options,
213 NULL);
214 if (tevent_req_nomem(subreq, req)) {
215 return tevent_req_post(req, ev);
217 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
218 return req;
221 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
223 struct tevent_req *req = tevent_req_callback_data(
224 subreq, struct tevent_req);
225 struct cli_smb2_create_fnum_state *state = tevent_req_data(
226 req, struct cli_smb2_create_fnum_state);
227 struct smb2_hnd h;
228 NTSTATUS status;
230 status = smb2cli_create_recv(subreq, &h.fid_persistent,
231 &h.fid_volatile, &state->cr);
232 TALLOC_FREE(subreq);
233 if (tevent_req_nterror(req, status)) {
234 return;
237 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
238 if (tevent_req_nterror(req, status)) {
239 return;
241 tevent_req_done(req);
244 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
245 struct smb_create_returns *cr)
247 struct cli_smb2_create_fnum_state *state = tevent_req_data(
248 req, struct cli_smb2_create_fnum_state);
249 NTSTATUS status;
251 if (tevent_req_is_nterror(req, &status)) {
252 return status;
254 if (pfnum != NULL) {
255 *pfnum = state->fnum;
257 if (cr != NULL) {
258 *cr = state->cr;
260 return NT_STATUS_OK;
263 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
264 const char *fname,
265 uint32_t create_flags,
266 uint32_t desired_access,
267 uint32_t file_attributes,
268 uint32_t share_access,
269 uint32_t create_disposition,
270 uint32_t create_options,
271 uint16_t *pfid,
272 struct smb_create_returns *cr)
274 TALLOC_CTX *frame = talloc_stackframe();
275 struct tevent_context *ev;
276 struct tevent_req *req;
277 NTSTATUS status = NT_STATUS_NO_MEMORY;
279 if (smbXcli_conn_has_async_calls(cli->conn)) {
281 * Can't use sync call while an async call is in flight
283 status = NT_STATUS_INVALID_PARAMETER;
284 goto fail;
286 ev = samba_tevent_context_init(frame);
287 if (ev == NULL) {
288 goto fail;
290 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
291 desired_access, file_attributes,
292 share_access, create_disposition,
293 create_options);
294 if (req == NULL) {
295 goto fail;
297 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
298 goto fail;
300 status = cli_smb2_create_fnum_recv(req, pfid, cr);
301 fail:
302 TALLOC_FREE(frame);
303 return status;
306 /***************************************************************
307 Small wrapper that allows SMB2 close to use a uint16_t fnum.
308 Synchronous only.
309 ***************************************************************/
311 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
313 struct smb2_hnd *ph = NULL;
314 NTSTATUS status;
316 if (smbXcli_conn_has_async_calls(cli->conn)) {
318 * Can't use sync call while an async call is in flight
320 return NT_STATUS_INVALID_PARAMETER;
323 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
324 return NT_STATUS_INVALID_PARAMETER;
327 status = map_fnum_to_smb2_handle(cli,
328 fnum,
329 &ph);
330 if (!NT_STATUS_IS_OK(status)) {
331 return status;
334 status = smb2cli_close(cli->conn,
335 cli->timeout,
336 cli->smb2.session,
337 cli->smb2.tcon,
339 ph->fid_persistent,
340 ph->fid_volatile);
342 /* Delete the fnum -> handle mapping. */
343 if (NT_STATUS_IS_OK(status)) {
344 status = delete_smb2_handle_mapping(cli, &ph, fnum);
347 return status;
350 /***************************************************************
351 Small wrapper that allows SMB2 to create a directory
352 Synchronous only.
353 ***************************************************************/
355 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
357 NTSTATUS status;
358 uint16_t fnum;
360 if (smbXcli_conn_has_async_calls(cli->conn)) {
362 * Can't use sync call while an async call is in flight
364 return NT_STATUS_INVALID_PARAMETER;
367 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
368 return NT_STATUS_INVALID_PARAMETER;
371 status = cli_smb2_create_fnum(cli,
372 dname,
373 0, /* create_flags */
374 FILE_READ_ATTRIBUTES, /* desired_access */
375 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
376 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
377 FILE_CREATE, /* create_disposition */
378 FILE_DIRECTORY_FILE, /* create_options */
379 &fnum,
380 NULL);
382 if (!NT_STATUS_IS_OK(status)) {
383 return status;
385 return cli_smb2_close_fnum(cli, fnum);
388 /***************************************************************
389 Small wrapper that allows SMB2 to delete a directory
390 Synchronous only.
391 ***************************************************************/
393 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
395 NTSTATUS status;
396 uint16_t fnum;
398 if (smbXcli_conn_has_async_calls(cli->conn)) {
400 * Can't use sync call while an async call is in flight
402 return NT_STATUS_INVALID_PARAMETER;
405 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
406 return NT_STATUS_INVALID_PARAMETER;
409 status = cli_smb2_create_fnum(cli,
410 dname,
411 0, /* create_flags */
412 DELETE_ACCESS, /* desired_access */
413 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
414 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
415 FILE_OPEN, /* create_disposition */
416 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
417 &fnum,
418 NULL);
420 if (!NT_STATUS_IS_OK(status)) {
421 return status;
423 return cli_smb2_close_fnum(cli, fnum);
426 /***************************************************************
427 Small wrapper that allows SMB2 to unlink a pathname.
428 Synchronous only.
429 ***************************************************************/
431 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
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 fname,
449 0, /* create_flags */
450 DELETE_ACCESS, /* desired_access */
451 FILE_ATTRIBUTE_NORMAL, /* file attributes */
452 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
453 FILE_OPEN, /* create_disposition */
454 FILE_DELETE_ON_CLOSE, /* 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 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
466 ***************************************************************/
468 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
469 uint32_t dir_data_length,
470 struct file_info *finfo,
471 uint32_t *next_offset)
473 size_t namelen = 0;
474 size_t slen = 0;
475 size_t ret = 0;
477 if (dir_data_length < 4) {
478 return NT_STATUS_INFO_LENGTH_MISMATCH;
481 *next_offset = IVAL(dir_data, 0);
483 if (*next_offset > dir_data_length) {
484 return NT_STATUS_INFO_LENGTH_MISMATCH;
487 if (*next_offset != 0) {
488 /* Ensure we only read what in this record. */
489 dir_data_length = *next_offset;
492 if (dir_data_length < 105) {
493 return NT_STATUS_INFO_LENGTH_MISMATCH;
496 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
497 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
498 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
499 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
500 finfo->mode = CVAL(dir_data + 56, 0);
501 namelen = IVAL(dir_data + 60,0);
502 if (namelen > (dir_data_length - 104)) {
503 return NT_STATUS_INFO_LENGTH_MISMATCH;
505 slen = CVAL(dir_data + 68, 0);
506 if (slen > 24) {
507 return NT_STATUS_INFO_LENGTH_MISMATCH;
509 ret = pull_string_talloc(finfo,
510 dir_data,
511 FLAGS2_UNICODE_STRINGS,
512 &finfo->short_name,
513 dir_data + 70,
514 slen,
515 STR_UNICODE);
516 if (ret == (size_t)-1) {
517 /* Bad conversion. */
518 return NT_STATUS_INVALID_NETWORK_RESPONSE;
521 ret = pull_string_talloc(finfo,
522 dir_data,
523 FLAGS2_UNICODE_STRINGS,
524 &finfo->name,
525 dir_data + 104,
526 namelen,
527 STR_UNICODE);
528 if (ret == (size_t)-1) {
529 /* Bad conversion. */
530 return NT_STATUS_INVALID_NETWORK_RESPONSE;
532 return NT_STATUS_OK;
535 /*******************************************************************
536 Given a filename - get its directory name
537 ********************************************************************/
539 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
540 const char *dir,
541 char **parent,
542 const char **name)
544 char *p;
545 ptrdiff_t len;
547 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
549 if (p == NULL) {
550 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
551 return false;
553 if (name) {
554 *name = dir;
556 return true;
559 len = p-dir;
561 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
562 return false;
564 (*parent)[len] = '\0';
566 if (name) {
567 *name = p+1;
569 return true;
572 /***************************************************************
573 Wrapper that allows SMB2 to list a directory.
574 Synchronous only.
575 ***************************************************************/
577 NTSTATUS cli_smb2_list(struct cli_state *cli,
578 const char *pathname,
579 uint16_t attribute,
580 NTSTATUS (*fn)(const char *,
581 struct file_info *,
582 const char *,
583 void *),
584 void *state)
586 NTSTATUS status;
587 uint16_t fnum = 0xffff;
588 char *parent_dir = NULL;
589 const char *mask = NULL;
590 struct smb2_hnd *ph = NULL;
591 bool processed_file = false;
592 TALLOC_CTX *frame = talloc_stackframe();
593 TALLOC_CTX *subframe = NULL;
595 if (smbXcli_conn_has_async_calls(cli->conn)) {
597 * Can't use sync call while an async call is in flight
599 status = NT_STATUS_INVALID_PARAMETER;
600 goto fail;
603 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
604 status = NT_STATUS_INVALID_PARAMETER;
605 goto fail;
608 /* Get the directory name. */
609 if (!windows_parent_dirname(frame,
610 pathname,
611 &parent_dir,
612 &mask)) {
613 status = NT_STATUS_NO_MEMORY;
614 goto fail;
617 status = cli_smb2_create_fnum(cli,
618 parent_dir,
619 0, /* create_flags */
620 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
621 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
622 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
623 FILE_OPEN, /* create_disposition */
624 FILE_DIRECTORY_FILE, /* create_options */
625 &fnum,
626 NULL);
628 if (!NT_STATUS_IS_OK(status)) {
629 goto fail;
632 status = map_fnum_to_smb2_handle(cli,
633 fnum,
634 &ph);
635 if (!NT_STATUS_IS_OK(status)) {
636 goto fail;
639 do {
640 uint8_t *dir_data = NULL;
641 uint32_t dir_data_length = 0;
642 uint32_t next_offset = 0;
643 subframe = talloc_stackframe();
645 status = smb2cli_query_directory(cli->conn,
646 cli->timeout,
647 cli->smb2.session,
648 cli->smb2.tcon,
649 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
650 0, /* flags */
651 0, /* file_index */
652 ph->fid_persistent,
653 ph->fid_volatile,
654 mask,
655 0xffff,
656 subframe,
657 &dir_data,
658 &dir_data_length);
660 if (!NT_STATUS_IS_OK(status)) {
661 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
662 break;
664 goto fail;
667 do {
668 struct file_info *finfo = talloc_zero(subframe,
669 struct file_info);
671 if (finfo == NULL) {
672 status = NT_STATUS_NO_MEMORY;
673 goto fail;
676 status = parse_finfo_id_both_directory_info(dir_data,
677 dir_data_length,
678 finfo,
679 &next_offset);
681 if (!NT_STATUS_IS_OK(status)) {
682 goto fail;
685 if (dir_check_ftype((uint32_t)finfo->mode,
686 (uint32_t)attribute)) {
688 * Only process if attributes match.
689 * On SMB1 server does this, so on
690 * SMB2 we need to emulate in the
691 * client.
693 * https://bugzilla.samba.org/show_bug.cgi?id=10260
695 processed_file = true;
697 status = fn(cli->dfs_mountpoint,
698 finfo,
699 pathname,
700 state);
702 if (!NT_STATUS_IS_OK(status)) {
703 break;
707 TALLOC_FREE(finfo);
709 /* Move to next entry. */
710 if (next_offset) {
711 dir_data += next_offset;
712 dir_data_length -= next_offset;
714 } while (next_offset != 0);
716 TALLOC_FREE(subframe);
718 } while (NT_STATUS_IS_OK(status));
720 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
721 status = NT_STATUS_OK;
724 if (NT_STATUS_IS_OK(status) && !processed_file) {
726 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
727 * if no files match. Emulate this in the client.
729 status = NT_STATUS_NO_SUCH_FILE;
732 fail:
734 if (fnum != 0xffff) {
735 cli_smb2_close_fnum(cli, fnum);
737 TALLOC_FREE(subframe);
738 TALLOC_FREE(frame);
739 return status;
742 /***************************************************************
743 Wrapper that allows SMB2 to query a path info (basic level).
744 Synchronous only.
745 ***************************************************************/
747 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
748 const char *name,
749 SMB_STRUCT_STAT *sbuf,
750 uint32_t *attributes)
752 NTSTATUS status;
753 struct smb_create_returns cr;
754 uint16_t fnum = 0xffff;
755 size_t namelen = strlen(name);
757 if (smbXcli_conn_has_async_calls(cli->conn)) {
759 * Can't use sync call while an async call is in flight
761 return NT_STATUS_INVALID_PARAMETER;
764 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
765 return NT_STATUS_INVALID_PARAMETER;
768 /* SMB2 is pickier about pathnames. Ensure it doesn't
769 end in a '\' */
770 if (namelen > 0 && name[namelen-1] == '\\') {
771 char *modname = talloc_strdup(talloc_tos(), name);
772 modname[namelen-1] = '\0';
773 name = modname;
776 /* This is commonly used as a 'cd'. Try qpathinfo on
777 a directory handle first. */
779 status = cli_smb2_create_fnum(cli,
780 name,
781 0, /* create_flags */
782 FILE_READ_ATTRIBUTES, /* desired_access */
783 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
784 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
785 FILE_OPEN, /* create_disposition */
786 FILE_DIRECTORY_FILE, /* create_options */
787 &fnum,
788 &cr);
790 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
791 /* Maybe a file ? */
792 status = cli_smb2_create_fnum(cli,
793 name,
794 0, /* create_flags */
795 FILE_READ_ATTRIBUTES, /* desired_access */
796 0, /* file attributes */
797 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
798 FILE_OPEN, /* create_disposition */
799 0, /* create_options */
800 &fnum,
801 &cr);
804 if (!NT_STATUS_IS_OK(status)) {
805 return status;
808 cli_smb2_close_fnum(cli, fnum);
810 ZERO_STRUCTP(sbuf);
812 sbuf->st_ex_atime = nt_time_to_unix_timespec(&cr.last_access_time);
813 sbuf->st_ex_mtime = nt_time_to_unix_timespec(&cr.last_write_time);
814 sbuf->st_ex_ctime = nt_time_to_unix_timespec(&cr.change_time);
815 sbuf->st_ex_size = cr.end_of_file;
816 *attributes = cr.file_attributes;
818 return NT_STATUS_OK;
821 /***************************************************************
822 Helper function for pathname operations.
823 ***************************************************************/
825 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
826 const char *name,
827 uint32_t desired_access,
828 uint16_t *pfnum)
830 NTSTATUS status;
831 size_t namelen = strlen(name);
832 TALLOC_CTX *frame = talloc_stackframe();
834 /* SMB2 is pickier about pathnames. Ensure it doesn't
835 end in a '\' */
836 if (namelen > 0 && name[namelen-1] == '\\') {
837 char *modname = talloc_strdup(frame, name);
838 if (modname == NULL) {
839 status = NT_STATUS_NO_MEMORY;
840 goto fail;
842 modname[namelen-1] = '\0';
843 name = modname;
846 /* Try to open a file handle first. */
847 status = cli_smb2_create_fnum(cli,
848 name,
849 0, /* create_flags */
850 desired_access,
851 0, /* file attributes */
852 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
853 FILE_OPEN, /* create_disposition */
854 0, /* create_options */
855 pfnum,
856 NULL);
858 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
859 status = cli_smb2_create_fnum(cli,
860 name,
861 0, /* create_flags */
862 desired_access,
863 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
864 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
865 FILE_OPEN, /* create_disposition */
866 FILE_DIRECTORY_FILE, /* create_options */
867 pfnum,
868 NULL);
871 fail:
873 TALLOC_FREE(frame);
874 return status;
877 /***************************************************************
878 Wrapper that allows SMB2 to query a path info (ALTNAME level).
879 Synchronous only.
880 ***************************************************************/
882 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
883 const char *name,
884 fstring alt_name)
886 NTSTATUS status;
887 DATA_BLOB outbuf = data_blob_null;
888 uint16_t fnum = 0xffff;
889 struct smb2_hnd *ph = NULL;
890 uint32_t altnamelen = 0;
891 TALLOC_CTX *frame = talloc_stackframe();
893 if (smbXcli_conn_has_async_calls(cli->conn)) {
895 * Can't use sync call while an async call is in flight
897 status = NT_STATUS_INVALID_PARAMETER;
898 goto fail;
901 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
902 status = NT_STATUS_INVALID_PARAMETER;
903 goto fail;
906 status = get_fnum_from_path(cli,
907 name,
908 FILE_READ_ATTRIBUTES,
909 &fnum);
911 if (!NT_STATUS_IS_OK(status)) {
912 goto fail;
915 status = map_fnum_to_smb2_handle(cli,
916 fnum,
917 &ph);
918 if (!NT_STATUS_IS_OK(status)) {
919 goto fail;
922 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
923 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
925 status = smb2cli_query_info(cli->conn,
926 cli->timeout,
927 cli->smb2.session,
928 cli->smb2.tcon,
929 1, /* in_info_type */
930 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
931 0xFFFF, /* in_max_output_length */
932 NULL, /* in_input_buffer */
933 0, /* in_additional_info */
934 0, /* in_flags */
935 ph->fid_persistent,
936 ph->fid_volatile,
937 frame,
938 &outbuf);
940 if (!NT_STATUS_IS_OK(status)) {
941 goto fail;
944 /* Parse the reply. */
945 if (outbuf.length < 4) {
946 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
947 goto fail;
950 altnamelen = IVAL(outbuf.data, 0);
951 if (altnamelen > outbuf.length - 4) {
952 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
953 goto fail;
956 if (altnamelen > 0) {
957 size_t ret = 0;
958 char *short_name = NULL;
959 ret = pull_string_talloc(frame,
960 outbuf.data,
961 FLAGS2_UNICODE_STRINGS,
962 &short_name,
963 outbuf.data + 4,
964 altnamelen,
965 STR_UNICODE);
966 if (ret == (size_t)-1) {
967 /* Bad conversion. */
968 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
969 goto fail;
972 fstrcpy(alt_name, short_name);
973 } else {
974 alt_name[0] = '\0';
977 status = NT_STATUS_OK;
979 fail:
981 if (fnum != 0xffff) {
982 cli_smb2_close_fnum(cli, fnum);
984 TALLOC_FREE(frame);
985 return status;
989 /***************************************************************
990 Wrapper that allows SMB2 to query a fnum info (basic level).
991 Synchronous only.
992 ***************************************************************/
994 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
995 uint16_t fnum,
996 uint16_t *mode,
997 off_t *size,
998 struct timespec *create_time,
999 struct timespec *access_time,
1000 struct timespec *write_time,
1001 struct timespec *change_time,
1002 SMB_INO_T *ino)
1004 NTSTATUS status;
1005 DATA_BLOB outbuf = data_blob_null;
1006 struct smb2_hnd *ph = NULL;
1007 TALLOC_CTX *frame = talloc_stackframe();
1009 if (smbXcli_conn_has_async_calls(cli->conn)) {
1011 * Can't use sync call while an async call is in flight
1013 status = NT_STATUS_INVALID_PARAMETER;
1014 goto fail;
1017 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1018 status = NT_STATUS_INVALID_PARAMETER;
1019 goto fail;
1022 status = map_fnum_to_smb2_handle(cli,
1023 fnum,
1024 &ph);
1025 if (!NT_STATUS_IS_OK(status)) {
1026 goto fail;
1029 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1030 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1032 status = smb2cli_query_info(cli->conn,
1033 cli->timeout,
1034 cli->smb2.session,
1035 cli->smb2.tcon,
1036 1, /* in_info_type */
1037 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1038 0xFFFF, /* in_max_output_length */
1039 NULL, /* in_input_buffer */
1040 0, /* in_additional_info */
1041 0, /* in_flags */
1042 ph->fid_persistent,
1043 ph->fid_volatile,
1044 frame,
1045 &outbuf);
1046 if (!NT_STATUS_IS_OK(status)) {
1047 goto fail;
1050 /* Parse the reply. */
1051 if (outbuf.length < 0x60) {
1052 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1053 goto fail;
1056 if (create_time) {
1057 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1059 if (access_time) {
1060 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1062 if (write_time) {
1063 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1065 if (change_time) {
1066 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1068 if (mode) {
1069 uint32_t attr = IVAL(outbuf.data, 0x20);
1070 *mode = (uint16_t)attr;
1072 if (size) {
1073 uint64_t file_size = BVAL(outbuf.data, 0x30);
1074 *size = (off_t)file_size;
1076 if (ino) {
1077 uint64_t file_index = BVAL(outbuf.data, 0x40);
1078 *ino = (SMB_INO_T)file_index;
1081 fail:
1083 TALLOC_FREE(frame);
1084 return status;
1087 /***************************************************************
1088 Wrapper that allows SMB2 to query an fnum.
1089 Implement on top of cli_smb2_qfileinfo_basic().
1090 Synchronous only.
1091 ***************************************************************/
1093 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1094 uint16_t fnum,
1095 uint16_t *attr,
1096 off_t *size,
1097 time_t *change_time,
1098 time_t *access_time,
1099 time_t *write_time)
1101 struct timespec access_time_ts;
1102 struct timespec write_time_ts;
1103 struct timespec change_time_ts;
1104 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1105 fnum,
1106 attr,
1107 size,
1108 NULL,
1109 &access_time_ts,
1110 &write_time_ts,
1111 &change_time_ts,
1112 NULL);
1114 if (!NT_STATUS_IS_OK(status)) {
1115 return status;
1118 if (change_time) {
1119 *change_time = change_time_ts.tv_sec;
1121 if (access_time) {
1122 *access_time = access_time_ts.tv_sec;
1124 if (write_time) {
1125 *write_time = write_time_ts.tv_sec;
1127 return NT_STATUS_OK;
1130 /***************************************************************
1131 Wrapper that allows SMB2 to get pathname attributes.
1132 Synchronous only.
1133 ***************************************************************/
1135 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1136 const char *name,
1137 uint16_t *attr,
1138 off_t *size,
1139 time_t *write_time)
1141 NTSTATUS status;
1142 uint16_t fnum = 0xffff;
1143 struct smb2_hnd *ph = NULL;
1144 TALLOC_CTX *frame = talloc_stackframe();
1146 if (smbXcli_conn_has_async_calls(cli->conn)) {
1148 * Can't use sync call while an async call is in flight
1150 status = NT_STATUS_INVALID_PARAMETER;
1151 goto fail;
1154 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1155 status = NT_STATUS_INVALID_PARAMETER;
1156 goto fail;
1159 status = get_fnum_from_path(cli,
1160 name,
1161 FILE_READ_ATTRIBUTES,
1162 &fnum);
1164 if (!NT_STATUS_IS_OK(status)) {
1165 goto fail;
1168 status = map_fnum_to_smb2_handle(cli,
1169 fnum,
1170 &ph);
1171 if (!NT_STATUS_IS_OK(status)) {
1172 goto fail;
1174 status = cli_smb2_getattrE(cli,
1175 fnum,
1176 attr,
1177 size,
1178 NULL,
1179 NULL,
1180 write_time);
1181 if (!NT_STATUS_IS_OK(status)) {
1182 goto fail;
1185 fail:
1187 if (fnum != 0xffff) {
1188 cli_smb2_close_fnum(cli, fnum);
1191 TALLOC_FREE(frame);
1192 return status;
1195 /***************************************************************
1196 Wrapper that allows SMB2 to query a pathname info (basic level).
1197 Implement on top of cli_smb2_qfileinfo_basic().
1198 Synchronous only.
1199 ***************************************************************/
1201 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1202 const char *name,
1203 struct timespec *create_time,
1204 struct timespec *access_time,
1205 struct timespec *write_time,
1206 struct timespec *change_time,
1207 off_t *size,
1208 uint16_t *mode,
1209 SMB_INO_T *ino)
1211 NTSTATUS status;
1212 struct smb2_hnd *ph = NULL;
1213 uint16_t fnum = 0xffff;
1214 TALLOC_CTX *frame = talloc_stackframe();
1216 if (smbXcli_conn_has_async_calls(cli->conn)) {
1218 * Can't use sync call while an async call is in flight
1220 status = NT_STATUS_INVALID_PARAMETER;
1221 goto fail;
1224 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1225 status = NT_STATUS_INVALID_PARAMETER;
1226 goto fail;
1229 status = get_fnum_from_path(cli,
1230 name,
1231 FILE_READ_ATTRIBUTES,
1232 &fnum);
1234 if (!NT_STATUS_IS_OK(status)) {
1235 goto fail;
1238 status = map_fnum_to_smb2_handle(cli,
1239 fnum,
1240 &ph);
1241 if (!NT_STATUS_IS_OK(status)) {
1242 goto fail;
1245 status = cli_smb2_qfileinfo_basic(cli,
1246 fnum,
1247 mode,
1248 size,
1249 create_time,
1250 access_time,
1251 write_time,
1252 change_time,
1253 ino);
1255 fail:
1257 if (fnum != 0xffff) {
1258 cli_smb2_close_fnum(cli, fnum);
1261 TALLOC_FREE(frame);
1262 return status;
1265 /***************************************************************
1266 Wrapper that allows SMB2 to query pathname streams.
1267 Synchronous only.
1268 ***************************************************************/
1270 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1271 const char *name,
1272 TALLOC_CTX *mem_ctx,
1273 unsigned int *pnum_streams,
1274 struct stream_struct **pstreams)
1276 NTSTATUS status;
1277 struct smb2_hnd *ph = NULL;
1278 uint16_t fnum = 0xffff;
1279 DATA_BLOB outbuf = data_blob_null;
1280 TALLOC_CTX *frame = talloc_stackframe();
1282 if (smbXcli_conn_has_async_calls(cli->conn)) {
1284 * Can't use sync call while an async call is in flight
1286 status = NT_STATUS_INVALID_PARAMETER;
1287 goto fail;
1290 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1291 status = NT_STATUS_INVALID_PARAMETER;
1292 goto fail;
1295 status = get_fnum_from_path(cli,
1296 name,
1297 FILE_READ_ATTRIBUTES,
1298 &fnum);
1300 if (!NT_STATUS_IS_OK(status)) {
1301 goto fail;
1304 status = map_fnum_to_smb2_handle(cli,
1305 fnum,
1306 &ph);
1307 if (!NT_STATUS_IS_OK(status)) {
1308 goto fail;
1311 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1312 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1314 status = smb2cli_query_info(cli->conn,
1315 cli->timeout,
1316 cli->smb2.session,
1317 cli->smb2.tcon,
1318 1, /* in_info_type */
1319 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1320 0xFFFF, /* in_max_output_length */
1321 NULL, /* in_input_buffer */
1322 0, /* in_additional_info */
1323 0, /* in_flags */
1324 ph->fid_persistent,
1325 ph->fid_volatile,
1326 frame,
1327 &outbuf);
1329 if (!NT_STATUS_IS_OK(status)) {
1330 goto fail;
1333 /* Parse the reply. */
1334 if (!parse_streams_blob(mem_ctx,
1335 outbuf.data,
1336 outbuf.length,
1337 pnum_streams,
1338 pstreams)) {
1339 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1340 goto fail;
1343 fail:
1345 if (fnum != 0xffff) {
1346 cli_smb2_close_fnum(cli, fnum);
1349 TALLOC_FREE(frame);
1350 return status;
1353 /***************************************************************
1354 Wrapper that allows SMB2 to set pathname attributes.
1355 Synchronous only.
1356 ***************************************************************/
1358 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1359 const char *name,
1360 uint16_t attr,
1361 time_t mtime)
1363 NTSTATUS status;
1364 uint16_t fnum = 0xffff;
1365 struct smb2_hnd *ph = NULL;
1366 uint8_t inbuf_store[40];
1367 DATA_BLOB inbuf = data_blob_null;
1368 TALLOC_CTX *frame = talloc_stackframe();
1370 if (smbXcli_conn_has_async_calls(cli->conn)) {
1372 * Can't use sync call while an async call is in flight
1374 status = NT_STATUS_INVALID_PARAMETER;
1375 goto fail;
1378 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1379 status = NT_STATUS_INVALID_PARAMETER;
1380 goto fail;
1383 status = get_fnum_from_path(cli,
1384 name,
1385 FILE_WRITE_ATTRIBUTES,
1386 &fnum);
1388 if (!NT_STATUS_IS_OK(status)) {
1389 goto fail;
1392 status = map_fnum_to_smb2_handle(cli,
1393 fnum,
1394 &ph);
1395 if (!NT_STATUS_IS_OK(status)) {
1396 goto fail;
1399 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1400 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1402 inbuf.data = inbuf_store;
1403 inbuf.length = sizeof(inbuf_store);
1404 data_blob_clear(&inbuf);
1406 SSVAL(inbuf.data, 32, attr);
1407 if (mtime != 0) {
1408 put_long_date((char *)inbuf.data + 16,mtime);
1410 /* Set all the other times to -1. */
1411 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1412 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1413 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1415 status = smb2cli_set_info(cli->conn,
1416 cli->timeout,
1417 cli->smb2.session,
1418 cli->smb2.tcon,
1419 1, /* in_info_type */
1420 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1421 &inbuf, /* in_input_buffer */
1422 0, /* in_additional_info */
1423 ph->fid_persistent,
1424 ph->fid_volatile);
1425 fail:
1427 if (fnum != 0xffff) {
1428 cli_smb2_close_fnum(cli, fnum);
1431 TALLOC_FREE(frame);
1432 return status;
1435 /***************************************************************
1436 Wrapper that allows SMB2 to set file handle times.
1437 Synchronous only.
1438 ***************************************************************/
1440 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1441 uint16_t fnum,
1442 time_t change_time,
1443 time_t access_time,
1444 time_t write_time)
1446 NTSTATUS status;
1447 struct smb2_hnd *ph = NULL;
1448 uint8_t inbuf_store[40];
1449 DATA_BLOB inbuf = data_blob_null;
1451 if (smbXcli_conn_has_async_calls(cli->conn)) {
1453 * Can't use sync call while an async call is in flight
1455 return NT_STATUS_INVALID_PARAMETER;
1458 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1459 return NT_STATUS_INVALID_PARAMETER;
1462 status = map_fnum_to_smb2_handle(cli,
1463 fnum,
1464 &ph);
1465 if (!NT_STATUS_IS_OK(status)) {
1466 return status;
1469 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1470 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1472 inbuf.data = inbuf_store;
1473 inbuf.length = sizeof(inbuf_store);
1474 data_blob_clear(&inbuf);
1476 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1477 if (change_time != 0) {
1478 put_long_date((char *)inbuf.data + 24, change_time);
1480 if (access_time != 0) {
1481 put_long_date((char *)inbuf.data + 8, access_time);
1483 if (write_time != 0) {
1484 put_long_date((char *)inbuf.data + 16, write_time);
1487 return smb2cli_set_info(cli->conn,
1488 cli->timeout,
1489 cli->smb2.session,
1490 cli->smb2.tcon,
1491 1, /* in_info_type */
1492 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1493 &inbuf, /* in_input_buffer */
1494 0, /* in_additional_info */
1495 ph->fid_persistent,
1496 ph->fid_volatile);
1499 /***************************************************************
1500 Wrapper that allows SMB2 to query disk attributes (size).
1501 Synchronous only.
1502 ***************************************************************/
1504 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, uint64_t *bsize, uint64_t *total, uint64_t *avail)
1506 NTSTATUS status;
1507 uint16_t fnum = 0xffff;
1508 DATA_BLOB outbuf = data_blob_null;
1509 struct smb2_hnd *ph = NULL;
1510 uint32_t sectors_per_unit = 0;
1511 uint32_t bytes_per_sector = 0;
1512 uint64_t total_size = 0;
1513 uint64_t size_free = 0;
1514 TALLOC_CTX *frame = talloc_stackframe();
1516 if (smbXcli_conn_has_async_calls(cli->conn)) {
1518 * Can't use sync call while an async call is in flight
1520 status = NT_STATUS_INVALID_PARAMETER;
1521 goto fail;
1524 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1525 status = NT_STATUS_INVALID_PARAMETER;
1526 goto fail;
1529 /* First open the top level directory. */
1530 status = cli_smb2_create_fnum(cli,
1532 0, /* create_flags */
1533 FILE_READ_ATTRIBUTES, /* desired_access */
1534 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1535 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1536 FILE_OPEN, /* create_disposition */
1537 FILE_DIRECTORY_FILE, /* create_options */
1538 &fnum,
1539 NULL);
1541 if (!NT_STATUS_IS_OK(status)) {
1542 goto fail;
1545 status = map_fnum_to_smb2_handle(cli,
1546 fnum,
1547 &ph);
1548 if (!NT_STATUS_IS_OK(status)) {
1549 goto fail;
1552 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1553 level 3 (SMB_FS_SIZE_INFORMATION). */
1555 status = smb2cli_query_info(cli->conn,
1556 cli->timeout,
1557 cli->smb2.session,
1558 cli->smb2.tcon,
1559 2, /* in_info_type */
1560 3, /* in_file_info_class */
1561 0xFFFF, /* in_max_output_length */
1562 NULL, /* in_input_buffer */
1563 0, /* in_additional_info */
1564 0, /* in_flags */
1565 ph->fid_persistent,
1566 ph->fid_volatile,
1567 frame,
1568 &outbuf);
1569 if (!NT_STATUS_IS_OK(status)) {
1570 goto fail;
1573 /* Parse the reply. */
1574 if (outbuf.length != 24) {
1575 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1576 goto fail;
1579 total_size = BVAL(outbuf.data, 0);
1580 size_free = BVAL(outbuf.data, 8);
1581 sectors_per_unit = IVAL(outbuf.data, 16);
1582 bytes_per_sector = IVAL(outbuf.data, 20);
1584 if (bsize) {
1585 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1587 if (total) {
1588 *total = total_size;
1590 if (avail) {
1591 *avail = size_free;
1594 status = NT_STATUS_OK;
1596 fail:
1598 if (fnum != 0xffff) {
1599 cli_smb2_close_fnum(cli, fnum);
1602 TALLOC_FREE(frame);
1603 return status;
1606 /***************************************************************
1607 Wrapper that allows SMB2 to query a security descriptor.
1608 Synchronous only.
1609 ***************************************************************/
1611 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1612 uint16_t fnum,
1613 uint32_t sec_info,
1614 TALLOC_CTX *mem_ctx,
1615 struct security_descriptor **ppsd)
1617 NTSTATUS status;
1618 DATA_BLOB outbuf = data_blob_null;
1619 struct smb2_hnd *ph = NULL;
1620 struct security_descriptor *lsd = NULL;
1621 TALLOC_CTX *frame = talloc_stackframe();
1623 if (smbXcli_conn_has_async_calls(cli->conn)) {
1625 * Can't use sync call while an async call is in flight
1627 status = NT_STATUS_INVALID_PARAMETER;
1628 goto fail;
1631 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1632 status = NT_STATUS_INVALID_PARAMETER;
1633 goto fail;
1636 status = map_fnum_to_smb2_handle(cli,
1637 fnum,
1638 &ph);
1639 if (!NT_STATUS_IS_OK(status)) {
1640 goto fail;
1643 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1645 status = smb2cli_query_info(cli->conn,
1646 cli->timeout,
1647 cli->smb2.session,
1648 cli->smb2.tcon,
1649 3, /* in_info_type */
1650 0, /* in_file_info_class */
1651 0xFFFF, /* in_max_output_length */
1652 NULL, /* in_input_buffer */
1653 sec_info, /* in_additional_info */
1654 0, /* in_flags */
1655 ph->fid_persistent,
1656 ph->fid_volatile,
1657 frame,
1658 &outbuf);
1660 if (!NT_STATUS_IS_OK(status)) {
1661 goto fail;
1664 /* Parse the reply. */
1665 status = unmarshall_sec_desc(mem_ctx,
1666 outbuf.data,
1667 outbuf.length,
1668 &lsd);
1670 if (!NT_STATUS_IS_OK(status)) {
1671 goto fail;
1674 if (ppsd != NULL) {
1675 *ppsd = lsd;
1676 } else {
1677 TALLOC_FREE(lsd);
1680 fail:
1682 TALLOC_FREE(frame);
1683 return status;
1686 /***************************************************************
1687 Wrapper that allows SMB2 to set a security descriptor.
1688 Synchronous only.
1689 ***************************************************************/
1691 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1692 uint16_t fnum,
1693 uint32_t sec_info,
1694 const struct security_descriptor *sd)
1696 NTSTATUS status;
1697 DATA_BLOB inbuf = data_blob_null;
1698 struct smb2_hnd *ph = NULL;
1699 TALLOC_CTX *frame = talloc_stackframe();
1701 if (smbXcli_conn_has_async_calls(cli->conn)) {
1703 * Can't use sync call while an async call is in flight
1705 status = NT_STATUS_INVALID_PARAMETER;
1706 goto fail;
1709 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1710 status = NT_STATUS_INVALID_PARAMETER;
1711 goto fail;
1714 status = map_fnum_to_smb2_handle(cli,
1715 fnum,
1716 &ph);
1717 if (!NT_STATUS_IS_OK(status)) {
1718 goto fail;
1721 status = marshall_sec_desc(frame,
1723 &inbuf.data,
1724 &inbuf.length);
1726 if (!NT_STATUS_IS_OK(status)) {
1727 goto fail;
1730 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1732 status = smb2cli_set_info(cli->conn,
1733 cli->timeout,
1734 cli->smb2.session,
1735 cli->smb2.tcon,
1736 3, /* in_info_type */
1737 0, /* in_file_info_class */
1738 &inbuf, /* in_input_buffer */
1739 sec_info, /* in_additional_info */
1740 ph->fid_persistent,
1741 ph->fid_volatile);
1743 fail:
1745 TALLOC_FREE(frame);
1746 return status;
1749 /***************************************************************
1750 Wrapper that allows SMB2 to rename a file.
1751 Synchronous only.
1752 ***************************************************************/
1754 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1755 const char *fname_src,
1756 const char *fname_dst)
1758 NTSTATUS status;
1759 DATA_BLOB inbuf = data_blob_null;
1760 uint16_t fnum = 0xffff;
1761 struct smb2_hnd *ph = NULL;
1762 smb_ucs2_t *converted_str = NULL;
1763 size_t converted_size_bytes = 0;
1764 size_t namelen = 0;
1765 TALLOC_CTX *frame = talloc_stackframe();
1767 if (smbXcli_conn_has_async_calls(cli->conn)) {
1769 * Can't use sync call while an async call is in flight
1771 status = NT_STATUS_INVALID_PARAMETER;
1772 goto fail;
1775 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1776 status = NT_STATUS_INVALID_PARAMETER;
1777 goto fail;
1780 status = get_fnum_from_path(cli,
1781 fname_src,
1782 DELETE_ACCESS,
1783 &fnum);
1785 if (!NT_STATUS_IS_OK(status)) {
1786 goto fail;
1789 status = map_fnum_to_smb2_handle(cli,
1790 fnum,
1791 &ph);
1792 if (!NT_STATUS_IS_OK(status)) {
1793 goto fail;
1796 /* SMB2 is pickier about pathnames. Ensure it doesn't
1797 start in a '\' */
1798 if (*fname_dst == '\\') {
1799 fname_dst++;
1802 /* SMB2 is pickier about pathnames. Ensure it doesn't
1803 end in a '\' */
1804 namelen = strlen(fname_dst);
1805 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
1806 char *modname = talloc_strdup(frame, fname_dst);
1807 modname[namelen-1] = '\0';
1808 fname_dst = modname;
1811 if (!push_ucs2_talloc(frame,
1812 &converted_str,
1813 fname_dst,
1814 &converted_size_bytes)) {
1815 status = NT_STATUS_INVALID_PARAMETER;
1816 goto fail;
1819 /* W2K8 insists the dest name is not null
1820 terminated. Remove the last 2 zero bytes
1821 and reduce the name length. */
1823 if (converted_size_bytes < 2) {
1824 status = NT_STATUS_INVALID_PARAMETER;
1825 goto fail;
1827 converted_size_bytes -= 2;
1829 inbuf = data_blob_talloc_zero(frame,
1830 20 + converted_size_bytes);
1831 if (inbuf.data == NULL) {
1832 status = NT_STATUS_NO_MEMORY;
1833 goto fail;
1836 SIVAL(inbuf.data, 16, converted_size_bytes);
1837 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
1839 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1840 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1842 status = smb2cli_set_info(cli->conn,
1843 cli->timeout,
1844 cli->smb2.session,
1845 cli->smb2.tcon,
1846 1, /* in_info_type */
1847 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
1848 &inbuf, /* in_input_buffer */
1849 0, /* in_additional_info */
1850 ph->fid_persistent,
1851 ph->fid_volatile);
1853 fail:
1855 if (fnum != 0xffff) {
1856 cli_smb2_close_fnum(cli, fnum);
1859 TALLOC_FREE(frame);
1860 return status;
1863 /***************************************************************
1864 Wrapper that allows SMB2 to set an EA on a fnum.
1865 Synchronous only.
1866 ***************************************************************/
1868 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
1869 uint16_t fnum,
1870 const char *ea_name,
1871 const char *ea_val,
1872 size_t ea_len)
1874 NTSTATUS status;
1875 DATA_BLOB inbuf = data_blob_null;
1876 size_t bloblen = 0;
1877 char *ea_name_ascii = NULL;
1878 size_t namelen = 0;
1879 struct smb2_hnd *ph = NULL;
1880 TALLOC_CTX *frame = talloc_stackframe();
1882 if (smbXcli_conn_has_async_calls(cli->conn)) {
1884 * Can't use sync call while an async call is in flight
1886 status = NT_STATUS_INVALID_PARAMETER;
1887 goto fail;
1890 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1891 status = NT_STATUS_INVALID_PARAMETER;
1892 goto fail;
1895 status = map_fnum_to_smb2_handle(cli,
1896 fnum,
1897 &ph);
1898 if (!NT_STATUS_IS_OK(status)) {
1899 goto fail;
1902 /* Marshall the SMB2 EA data. */
1903 if (ea_len > 0xFFFF) {
1904 status = NT_STATUS_INVALID_PARAMETER;
1905 goto fail;
1908 if (!push_ascii_talloc(frame,
1909 &ea_name_ascii,
1910 ea_name,
1911 &namelen)) {
1912 status = NT_STATUS_INVALID_PARAMETER;
1913 goto fail;
1916 if (namelen < 2 || namelen > 0xFF) {
1917 status = NT_STATUS_INVALID_PARAMETER;
1918 goto fail;
1921 bloblen = 8 + ea_len + namelen;
1922 /* Round up to a 4 byte boundary. */
1923 bloblen = ((bloblen + 3)&~3);
1925 inbuf = data_blob_talloc_zero(frame, bloblen);
1926 if (inbuf.data == NULL) {
1927 status = NT_STATUS_NO_MEMORY;
1928 goto fail;
1930 /* namelen doesn't include the NULL byte. */
1931 SCVAL(inbuf.data, 5, namelen - 1);
1932 SSVAL(inbuf.data, 6, ea_len);
1933 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
1934 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
1936 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1937 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
1939 status = smb2cli_set_info(cli->conn,
1940 cli->timeout,
1941 cli->smb2.session,
1942 cli->smb2.tcon,
1943 1, /* in_info_type */
1944 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
1945 &inbuf, /* in_input_buffer */
1946 0, /* in_additional_info */
1947 ph->fid_persistent,
1948 ph->fid_volatile);
1950 fail:
1952 TALLOC_FREE(frame);
1953 return status;
1956 /***************************************************************
1957 Wrapper that allows SMB2 to set an EA on a pathname.
1958 Synchronous only.
1959 ***************************************************************/
1961 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
1962 const char *name,
1963 const char *ea_name,
1964 const char *ea_val,
1965 size_t ea_len)
1967 NTSTATUS status;
1968 uint16_t fnum = 0xffff;
1970 if (smbXcli_conn_has_async_calls(cli->conn)) {
1972 * Can't use sync call while an async call is in flight
1974 status = NT_STATUS_INVALID_PARAMETER;
1975 goto fail;
1978 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1979 status = NT_STATUS_INVALID_PARAMETER;
1980 goto fail;
1983 status = get_fnum_from_path(cli,
1984 name,
1985 FILE_WRITE_EA,
1986 &fnum);
1988 if (!NT_STATUS_IS_OK(status)) {
1989 goto fail;
1992 status = cli_set_ea_fnum(cli,
1993 fnum,
1994 ea_name,
1995 ea_val,
1996 ea_len);
1997 if (!NT_STATUS_IS_OK(status)) {
1998 goto fail;
2001 fail:
2003 if (fnum != 0xffff) {
2004 cli_smb2_close_fnum(cli, fnum);
2007 return status;
2010 /***************************************************************
2011 Wrapper that allows SMB2 to get an EA list on a pathname.
2012 Synchronous only.
2013 ***************************************************************/
2015 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2016 const char *name,
2017 TALLOC_CTX *ctx,
2018 size_t *pnum_eas,
2019 struct ea_struct **pea_array)
2021 NTSTATUS status;
2022 uint16_t fnum = 0xffff;
2023 DATA_BLOB outbuf = data_blob_null;
2024 struct smb2_hnd *ph = NULL;
2025 struct ea_list *ea_list = NULL;
2026 struct ea_list *eal = NULL;
2027 size_t ea_count = 0;
2028 TALLOC_CTX *frame = talloc_stackframe();
2030 *pnum_eas = 0;
2031 *pea_array = NULL;
2033 if (smbXcli_conn_has_async_calls(cli->conn)) {
2035 * Can't use sync call while an async call is in flight
2037 status = NT_STATUS_INVALID_PARAMETER;
2038 goto fail;
2041 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2042 status = NT_STATUS_INVALID_PARAMETER;
2043 goto fail;
2046 status = get_fnum_from_path(cli,
2047 name,
2048 FILE_READ_EA,
2049 &fnum);
2051 if (!NT_STATUS_IS_OK(status)) {
2052 goto fail;
2055 status = map_fnum_to_smb2_handle(cli,
2056 fnum,
2057 &ph);
2058 if (!NT_STATUS_IS_OK(status)) {
2059 goto fail;
2062 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2063 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2065 status = smb2cli_query_info(cli->conn,
2066 cli->timeout,
2067 cli->smb2.session,
2068 cli->smb2.tcon,
2069 1, /* in_info_type */
2070 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2071 0xFFFF, /* in_max_output_length */
2072 NULL, /* in_input_buffer */
2073 0, /* in_additional_info */
2074 0, /* in_flags */
2075 ph->fid_persistent,
2076 ph->fid_volatile,
2077 frame,
2078 &outbuf);
2080 if (!NT_STATUS_IS_OK(status)) {
2081 goto fail;
2084 /* Parse the reply. */
2085 ea_list = read_nttrans_ea_list(ctx,
2086 (const char *)outbuf.data,
2087 outbuf.length);
2088 if (ea_list == NULL) {
2089 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2090 goto fail;
2093 /* Convert to an array. */
2094 for (eal = ea_list; eal; eal = eal->next) {
2095 ea_count++;
2098 if (ea_count) {
2099 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2100 if (*pea_array == NULL) {
2101 status = NT_STATUS_NO_MEMORY;
2102 goto fail;
2104 ea_count = 0;
2105 for (eal = ea_list; eal; eal = eal->next) {
2106 (*pea_array)[ea_count++] = ea_list->ea;
2108 *pnum_eas = ea_count;
2111 fail:
2113 if (fnum != 0xffff) {
2114 cli_smb2_close_fnum(cli, fnum);
2117 TALLOC_FREE(frame);
2118 return status;
2121 struct cli_smb2_read_state {
2122 struct tevent_context *ev;
2123 struct cli_state *cli;
2124 struct smb2_hnd *ph;
2125 uint64_t start_offset;
2126 uint32_t size;
2127 uint32_t received;
2128 uint8_t *buf;
2131 static void cli_smb2_read_done(struct tevent_req *subreq);
2133 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2134 struct tevent_context *ev,
2135 struct cli_state *cli,
2136 uint16_t fnum,
2137 off_t offset,
2138 size_t size)
2140 NTSTATUS status;
2141 struct tevent_req *req, *subreq;
2142 struct cli_smb2_read_state *state;
2144 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2145 if (req == NULL) {
2146 return NULL;
2148 state->ev = ev;
2149 state->cli = cli;
2150 state->start_offset = (uint64_t)offset;
2151 state->size = (uint32_t)size;
2152 state->received = 0;
2153 state->buf = NULL;
2155 status = map_fnum_to_smb2_handle(cli,
2156 fnum,
2157 &state->ph);
2158 if (tevent_req_nterror(req, status)) {
2159 return tevent_req_post(req, ev);
2162 subreq = smb2cli_read_send(state,
2163 state->ev,
2164 state->cli->conn,
2165 state->cli->timeout,
2166 state->cli->smb2.session,
2167 state->cli->smb2.tcon,
2168 state->size,
2169 state->start_offset,
2170 state->ph->fid_persistent,
2171 state->ph->fid_volatile,
2172 0, /* minimum_count */
2173 0); /* remaining_bytes */
2175 if (tevent_req_nomem(subreq, req)) {
2176 return tevent_req_post(req, ev);
2178 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2179 return req;
2182 static void cli_smb2_read_done(struct tevent_req *subreq)
2184 struct tevent_req *req = tevent_req_callback_data(
2185 subreq, struct tevent_req);
2186 struct cli_smb2_read_state *state = tevent_req_data(
2187 req, struct cli_smb2_read_state);
2188 NTSTATUS status;
2190 status = smb2cli_read_recv(subreq, state,
2191 &state->buf, &state->received);
2192 if (tevent_req_nterror(req, status)) {
2193 return;
2196 if (state->received > state->size) {
2197 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2198 return;
2201 tevent_req_done(req);
2204 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2205 ssize_t *received,
2206 uint8_t **rcvbuf)
2208 NTSTATUS status;
2209 struct cli_smb2_read_state *state = tevent_req_data(
2210 req, struct cli_smb2_read_state);
2212 if (tevent_req_is_nterror(req, &status)) {
2213 return status;
2216 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2217 * better make sure that you copy it away before you talloc_free(req).
2218 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2220 *received = (ssize_t)state->received;
2221 *rcvbuf = state->buf;
2222 return NT_STATUS_OK;
2225 struct cli_smb2_write_state {
2226 struct tevent_context *ev;
2227 struct cli_state *cli;
2228 struct smb2_hnd *ph;
2229 uint32_t flags;
2230 const uint8_t *buf;
2231 uint64_t offset;
2232 uint32_t size;
2233 uint32_t written;
2236 static void cli_smb2_write_written(struct tevent_req *req);
2238 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2239 struct tevent_context *ev,
2240 struct cli_state *cli,
2241 uint16_t fnum,
2242 uint16_t mode,
2243 const uint8_t *buf,
2244 off_t offset,
2245 size_t size)
2247 NTSTATUS status;
2248 struct tevent_req *req, *subreq = NULL;
2249 struct cli_smb2_write_state *state = NULL;
2251 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2252 if (req == NULL) {
2253 return NULL;
2255 state->ev = ev;
2256 state->cli = cli;
2257 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2258 state->flags = (uint32_t)mode;
2259 state->buf = buf;
2260 state->offset = (uint64_t)offset;
2261 state->size = (uint32_t)size;
2262 state->written = 0;
2264 status = map_fnum_to_smb2_handle(cli,
2265 fnum,
2266 &state->ph);
2267 if (tevent_req_nterror(req, status)) {
2268 return tevent_req_post(req, ev);
2271 subreq = smb2cli_write_send(state,
2272 state->ev,
2273 state->cli->conn,
2274 state->cli->timeout,
2275 state->cli->smb2.session,
2276 state->cli->smb2.tcon,
2277 state->size,
2278 state->offset,
2279 state->ph->fid_persistent,
2280 state->ph->fid_volatile,
2281 0, /* remaining_bytes */
2282 state->flags, /* flags */
2283 state->buf);
2285 if (tevent_req_nomem(subreq, req)) {
2286 return tevent_req_post(req, ev);
2288 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2289 return req;
2292 static void cli_smb2_write_written(struct tevent_req *subreq)
2294 struct tevent_req *req = tevent_req_callback_data(
2295 subreq, struct tevent_req);
2296 struct cli_smb2_write_state *state = tevent_req_data(
2297 req, struct cli_smb2_write_state);
2298 NTSTATUS status;
2299 uint32_t written;
2301 status = smb2cli_write_recv(subreq, &written);
2302 TALLOC_FREE(subreq);
2303 if (tevent_req_nterror(req, status)) {
2304 return;
2307 state->written = written;
2309 tevent_req_done(req);
2312 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2313 size_t *pwritten)
2315 struct cli_smb2_write_state *state = tevent_req_data(
2316 req, struct cli_smb2_write_state);
2317 NTSTATUS status;
2319 if (tevent_req_is_nterror(req, &status)) {
2320 tevent_req_received(req);
2321 return status;
2324 if (pwritten != NULL) {
2325 *pwritten = (size_t)state->written;
2327 tevent_req_received(req);
2328 return NT_STATUS_OK;
2331 /***************************************************************
2332 Wrapper that allows SMB2 async write using an fnum.
2333 This is mostly cut-and-paste from Volker's code inside
2334 source3/libsmb/clireadwrite.c, adapted for SMB2.
2336 Done this way so I can reuse all the logic inside cli_push()
2337 for free :-).
2338 ***************************************************************/
2340 struct cli_smb2_writeall_state {
2341 struct tevent_context *ev;
2342 struct cli_state *cli;
2343 struct smb2_hnd *ph;
2344 uint32_t flags;
2345 const uint8_t *buf;
2346 uint64_t offset;
2347 uint32_t size;
2348 uint32_t written;
2351 static void cli_smb2_writeall_written(struct tevent_req *req);
2353 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2354 struct tevent_context *ev,
2355 struct cli_state *cli,
2356 uint16_t fnum,
2357 uint16_t mode,
2358 const uint8_t *buf,
2359 off_t offset,
2360 size_t size)
2362 NTSTATUS status;
2363 struct tevent_req *req, *subreq = NULL;
2364 struct cli_smb2_writeall_state *state = NULL;
2365 uint32_t to_write;
2366 uint32_t max_size;
2367 bool ok;
2369 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2370 if (req == NULL) {
2371 return NULL;
2373 state->ev = ev;
2374 state->cli = cli;
2375 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2376 state->flags = (uint32_t)mode;
2377 state->buf = buf;
2378 state->offset = (uint64_t)offset;
2379 state->size = (uint32_t)size;
2380 state->written = 0;
2382 status = map_fnum_to_smb2_handle(cli,
2383 fnum,
2384 &state->ph);
2385 if (tevent_req_nterror(req, status)) {
2386 return tevent_req_post(req, ev);
2389 to_write = state->size;
2390 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2391 to_write = MIN(max_size, to_write);
2392 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2393 if (ok) {
2394 to_write = MIN(max_size, to_write);
2397 subreq = smb2cli_write_send(state,
2398 state->ev,
2399 state->cli->conn,
2400 state->cli->timeout,
2401 state->cli->smb2.session,
2402 state->cli->smb2.tcon,
2403 to_write,
2404 state->offset,
2405 state->ph->fid_persistent,
2406 state->ph->fid_volatile,
2407 0, /* remaining_bytes */
2408 state->flags, /* flags */
2409 state->buf + state->written);
2411 if (tevent_req_nomem(subreq, req)) {
2412 return tevent_req_post(req, ev);
2414 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2415 return req;
2418 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2420 struct tevent_req *req = tevent_req_callback_data(
2421 subreq, struct tevent_req);
2422 struct cli_smb2_writeall_state *state = tevent_req_data(
2423 req, struct cli_smb2_writeall_state);
2424 NTSTATUS status;
2425 uint32_t written, to_write;
2426 uint32_t max_size;
2427 bool ok;
2429 status = smb2cli_write_recv(subreq, &written);
2430 TALLOC_FREE(subreq);
2431 if (tevent_req_nterror(req, status)) {
2432 return;
2435 state->written += written;
2437 if (state->written > state->size) {
2438 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2439 return;
2442 to_write = state->size - state->written;
2444 if (to_write == 0) {
2445 tevent_req_done(req);
2446 return;
2449 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2450 to_write = MIN(max_size, to_write);
2451 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2452 if (ok) {
2453 to_write = MIN(max_size, to_write);
2456 subreq = smb2cli_write_send(state,
2457 state->ev,
2458 state->cli->conn,
2459 state->cli->timeout,
2460 state->cli->smb2.session,
2461 state->cli->smb2.tcon,
2462 to_write,
2463 state->offset + state->written,
2464 state->ph->fid_persistent,
2465 state->ph->fid_volatile,
2466 0, /* remaining_bytes */
2467 state->flags, /* flags */
2468 state->buf + state->written);
2470 if (tevent_req_nomem(subreq, req)) {
2471 return;
2473 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2476 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
2477 size_t *pwritten)
2479 struct cli_smb2_writeall_state *state = tevent_req_data(
2480 req, struct cli_smb2_writeall_state);
2481 NTSTATUS status;
2483 if (tevent_req_is_nterror(req, &status)) {
2484 return status;
2486 if (pwritten != NULL) {
2487 *pwritten = (size_t)state->written;
2489 return NT_STATUS_OK;