s4-dsdb: Initial implementation for Tombstone reanimation module
[Samba.git] / source3 / libsmb / cli_smb2_fnum.c
blobde4bd6feb62c2f39bf8a522e96c659d2cab36c20
1 /*
2 Unix SMB/CIFS implementation.
3 smb2 lib
4 Copyright (C) Jeremy Allison 2013
5 Copyright (C) Volker Lendecke 2013
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 This code is a thin wrapper around the existing
24 cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
25 but allows the handles to be mapped to uint16_t fnums,
26 which are easier for smbclient to use.
29 #include "includes.h"
30 #include "client.h"
31 #include "async_smb.h"
32 #include "../libcli/smb/smbXcli_base.h"
33 #include "cli_smb2_fnum.h"
34 #include "trans2.h"
35 #include "clirap.h"
36 #include "../libcli/smb/smb2_create_blob.h"
37 #include "libsmb/proto.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "../libcli/security/security.h"
40 #include "lib/util_ea.h"
42 struct smb2_hnd {
43 uint64_t fid_persistent;
44 uint64_t fid_volatile;
48 * Handle mapping code.
51 /***************************************************************
52 Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
53 Ensures handle is owned by cli struct.
54 ***************************************************************/
56 static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
57 const struct smb2_hnd *ph, /* In */
58 uint16_t *pfnum) /* Out */
60 int ret;
61 struct idr_context *idp = cli->smb2.open_handles;
62 struct smb2_hnd *owned_h = talloc_memdup(cli,
63 ph,
64 sizeof(struct smb2_hnd));
66 if (owned_h == NULL) {
67 return NT_STATUS_NO_MEMORY;
70 if (idp == NULL) {
71 /* Lazy init */
72 cli->smb2.open_handles = idr_init(cli);
73 if (cli->smb2.open_handles == NULL) {
74 TALLOC_FREE(owned_h);
75 return NT_STATUS_NO_MEMORY;
77 idp = cli->smb2.open_handles;
80 ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
81 if (ret == -1) {
82 TALLOC_FREE(owned_h);
83 return NT_STATUS_NO_MEMORY;
86 *pfnum = (uint16_t)ret;
87 return NT_STATUS_OK;
90 /***************************************************************
91 Return the smb2_hnd pointer associated with the given fnum.
92 ***************************************************************/
94 static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
95 uint16_t fnum, /* In */
96 struct smb2_hnd **pph) /* Out */
98 struct idr_context *idp = cli->smb2.open_handles;
100 if (idp == NULL) {
101 return NT_STATUS_INVALID_PARAMETER;
103 *pph = (struct smb2_hnd *)idr_find(idp, fnum);
104 if (*pph == NULL) {
105 return NT_STATUS_INVALID_HANDLE;
107 return NT_STATUS_OK;
110 /***************************************************************
111 Delete the fnum to smb2_hnd mapping. Zeros out handle on
112 successful return.
113 ***************************************************************/
115 static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
116 struct smb2_hnd **pph, /* In */
117 uint16_t fnum) /* In */
119 struct idr_context *idp = cli->smb2.open_handles;
120 struct smb2_hnd *ph;
122 if (idp == NULL) {
123 return NT_STATUS_INVALID_PARAMETER;
126 ph = (struct smb2_hnd *)idr_find(idp, fnum);
127 if (ph != *pph) {
128 return NT_STATUS_INVALID_PARAMETER;
130 idr_remove(idp, fnum);
131 TALLOC_FREE(*pph);
132 return NT_STATUS_OK;
135 /***************************************************************
136 Oplock mapping code.
137 ***************************************************************/
139 static uint8_t flags_to_smb2_oplock(uint32_t create_flags)
141 if (create_flags & REQUEST_BATCH_OPLOCK) {
142 return SMB2_OPLOCK_LEVEL_BATCH;
143 } else if (create_flags & REQUEST_OPLOCK) {
144 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
147 /* create_flags doesn't do a level2 request. */
148 return SMB2_OPLOCK_LEVEL_NONE;
151 /***************************************************************
152 Small wrapper that allows SMB2 create to return a uint16_t fnum.
153 ***************************************************************/
155 struct cli_smb2_create_fnum_state {
156 struct cli_state *cli;
157 struct smb_create_returns cr;
158 uint16_t fnum;
159 struct tevent_req *subreq;
162 static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
163 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
165 struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
166 struct tevent_context *ev,
167 struct cli_state *cli,
168 const char *fname,
169 uint32_t create_flags,
170 uint32_t desired_access,
171 uint32_t file_attributes,
172 uint32_t share_access,
173 uint32_t create_disposition,
174 uint32_t create_options)
176 struct tevent_req *req, *subreq;
177 struct cli_smb2_create_fnum_state *state;
179 req = tevent_req_create(mem_ctx, &state,
180 struct cli_smb2_create_fnum_state);
181 if (req == NULL) {
182 return NULL;
184 state->cli = cli;
186 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
187 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
188 return tevent_req_post(req, ev);
191 if (cli->backup_intent) {
192 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
195 /* SMB2 is pickier about pathnames. Ensure it doesn't
196 start in a '\' */
197 if (*fname == '\\') {
198 fname++;
201 subreq = smb2cli_create_send(state, ev,
202 cli->conn,
203 cli->timeout,
204 cli->smb2.session,
205 cli->smb2.tcon,
206 fname,
207 flags_to_smb2_oplock(create_flags),
208 SMB2_IMPERSONATION_IMPERSONATION,
209 desired_access,
210 file_attributes,
211 share_access,
212 create_disposition,
213 create_options,
214 NULL);
215 if (tevent_req_nomem(subreq, req)) {
216 return tevent_req_post(req, ev);
218 tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
220 state->subreq = subreq;
221 tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
223 return req;
226 static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
228 struct tevent_req *req = tevent_req_callback_data(
229 subreq, struct tevent_req);
230 struct cli_smb2_create_fnum_state *state = tevent_req_data(
231 req, struct cli_smb2_create_fnum_state);
232 struct smb2_hnd h;
233 NTSTATUS status;
235 status = smb2cli_create_recv(subreq, &h.fid_persistent,
236 &h.fid_volatile, &state->cr, NULL, NULL);
237 TALLOC_FREE(subreq);
238 if (tevent_req_nterror(req, status)) {
239 return;
242 status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
243 if (tevent_req_nterror(req, status)) {
244 return;
246 tevent_req_done(req);
249 static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
251 struct cli_smb2_create_fnum_state *state = tevent_req_data(
252 req, struct cli_smb2_create_fnum_state);
253 return tevent_req_cancel(state->subreq);
256 NTSTATUS cli_smb2_create_fnum_recv(struct tevent_req *req, uint16_t *pfnum,
257 struct smb_create_returns *cr)
259 struct cli_smb2_create_fnum_state *state = tevent_req_data(
260 req, struct cli_smb2_create_fnum_state);
261 NTSTATUS status;
263 if (tevent_req_is_nterror(req, &status)) {
264 return status;
266 if (pfnum != NULL) {
267 *pfnum = state->fnum;
269 if (cr != NULL) {
270 *cr = state->cr;
272 return NT_STATUS_OK;
275 NTSTATUS cli_smb2_create_fnum(struct cli_state *cli,
276 const char *fname,
277 uint32_t create_flags,
278 uint32_t desired_access,
279 uint32_t file_attributes,
280 uint32_t share_access,
281 uint32_t create_disposition,
282 uint32_t create_options,
283 uint16_t *pfid,
284 struct smb_create_returns *cr)
286 TALLOC_CTX *frame = talloc_stackframe();
287 struct tevent_context *ev;
288 struct tevent_req *req;
289 NTSTATUS status = NT_STATUS_NO_MEMORY;
291 if (smbXcli_conn_has_async_calls(cli->conn)) {
293 * Can't use sync call while an async call is in flight
295 status = NT_STATUS_INVALID_PARAMETER;
296 goto fail;
298 ev = samba_tevent_context_init(frame);
299 if (ev == NULL) {
300 goto fail;
302 req = cli_smb2_create_fnum_send(frame, ev, cli, fname, create_flags,
303 desired_access, file_attributes,
304 share_access, create_disposition,
305 create_options);
306 if (req == NULL) {
307 goto fail;
309 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
310 goto fail;
312 status = cli_smb2_create_fnum_recv(req, pfid, cr);
313 fail:
314 TALLOC_FREE(frame);
315 return status;
318 /***************************************************************
319 Small wrapper that allows SMB2 close to use a uint16_t fnum.
320 ***************************************************************/
322 struct cli_smb2_close_fnum_state {
323 struct cli_state *cli;
324 uint16_t fnum;
325 struct smb2_hnd *ph;
328 static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
330 struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
331 struct tevent_context *ev,
332 struct cli_state *cli,
333 uint16_t fnum)
335 struct tevent_req *req, *subreq;
336 struct cli_smb2_close_fnum_state *state;
337 NTSTATUS status;
339 req = tevent_req_create(mem_ctx, &state,
340 struct cli_smb2_close_fnum_state);
341 if (req == NULL) {
342 return NULL;
344 state->cli = cli;
345 state->fnum = fnum;
347 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
348 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
349 return tevent_req_post(req, ev);
352 status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
353 if (tevent_req_nterror(req, status)) {
354 return tevent_req_post(req, ev);
357 subreq = smb2cli_close_send(state, ev, cli->conn, cli->timeout,
358 cli->smb2.session, cli->smb2.tcon,
359 0, state->ph->fid_persistent,
360 state->ph->fid_volatile);
361 if (tevent_req_nomem(subreq, req)) {
362 return tevent_req_post(req, ev);
364 tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
365 return req;
368 static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
370 struct tevent_req *req = tevent_req_callback_data(
371 subreq, struct tevent_req);
372 struct cli_smb2_close_fnum_state *state = tevent_req_data(
373 req, struct cli_smb2_close_fnum_state);
374 NTSTATUS status;
376 status = smb2cli_close_recv(subreq);
377 if (tevent_req_nterror(req, status)) {
378 return;
381 /* Delete the fnum -> handle mapping. */
382 status = delete_smb2_handle_mapping(state->cli, &state->ph,
383 state->fnum);
384 if (tevent_req_nterror(req, status)) {
385 return;
387 tevent_req_done(req);
390 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
392 return tevent_req_simple_recv_ntstatus(req);
395 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
397 TALLOC_CTX *frame = talloc_stackframe();
398 struct tevent_context *ev;
399 struct tevent_req *req;
400 NTSTATUS status = NT_STATUS_NO_MEMORY;
402 if (smbXcli_conn_has_async_calls(cli->conn)) {
404 * Can't use sync call while an async call is in flight
406 status = NT_STATUS_INVALID_PARAMETER;
407 goto fail;
409 ev = samba_tevent_context_init(frame);
410 if (ev == NULL) {
411 goto fail;
413 req = cli_smb2_close_fnum_send(frame, ev, cli, fnum);
414 if (req == NULL) {
415 goto fail;
417 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
418 goto fail;
420 status = cli_smb2_close_fnum_recv(req);
421 fail:
422 TALLOC_FREE(frame);
423 return status;
426 /***************************************************************
427 Small wrapper that allows SMB2 to create a directory
428 Synchronous only.
429 ***************************************************************/
431 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname)
433 NTSTATUS status;
434 uint16_t fnum;
436 if (smbXcli_conn_has_async_calls(cli->conn)) {
438 * Can't use sync call while an async call is in flight
440 return NT_STATUS_INVALID_PARAMETER;
443 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
444 return NT_STATUS_INVALID_PARAMETER;
447 status = cli_smb2_create_fnum(cli,
448 dname,
449 0, /* create_flags */
450 FILE_READ_ATTRIBUTES, /* desired_access */
451 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
452 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
453 FILE_CREATE, /* create_disposition */
454 FILE_DIRECTORY_FILE, /* create_options */
455 &fnum,
456 NULL);
458 if (!NT_STATUS_IS_OK(status)) {
459 return status;
461 return cli_smb2_close_fnum(cli, fnum);
464 /***************************************************************
465 Small wrapper that allows SMB2 to delete a directory
466 Synchronous only.
467 ***************************************************************/
469 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
471 NTSTATUS status;
472 uint16_t fnum;
474 if (smbXcli_conn_has_async_calls(cli->conn)) {
476 * Can't use sync call while an async call is in flight
478 return NT_STATUS_INVALID_PARAMETER;
481 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
482 return NT_STATUS_INVALID_PARAMETER;
485 status = cli_smb2_create_fnum(cli,
486 dname,
487 0, /* create_flags */
488 DELETE_ACCESS, /* desired_access */
489 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
490 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
491 FILE_OPEN, /* create_disposition */
492 FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */
493 &fnum,
494 NULL);
496 if (!NT_STATUS_IS_OK(status)) {
497 return status;
499 return cli_smb2_close_fnum(cli, fnum);
502 /***************************************************************
503 Small wrapper that allows SMB2 to unlink a pathname.
504 Synchronous only.
505 ***************************************************************/
507 NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
509 NTSTATUS status;
510 uint16_t fnum;
512 if (smbXcli_conn_has_async_calls(cli->conn)) {
514 * Can't use sync call while an async call is in flight
516 return NT_STATUS_INVALID_PARAMETER;
519 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
520 return NT_STATUS_INVALID_PARAMETER;
523 status = cli_smb2_create_fnum(cli,
524 fname,
525 0, /* create_flags */
526 DELETE_ACCESS, /* desired_access */
527 FILE_ATTRIBUTE_NORMAL, /* file attributes */
528 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
529 FILE_OPEN, /* create_disposition */
530 FILE_DELETE_ON_CLOSE, /* create_options */
531 &fnum,
532 NULL);
534 if (!NT_STATUS_IS_OK(status)) {
535 return status;
537 return cli_smb2_close_fnum(cli, fnum);
540 /***************************************************************
541 Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
542 ***************************************************************/
544 static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
545 uint32_t dir_data_length,
546 struct file_info *finfo,
547 uint32_t *next_offset)
549 size_t namelen = 0;
550 size_t slen = 0;
551 size_t ret = 0;
553 if (dir_data_length < 4) {
554 return NT_STATUS_INFO_LENGTH_MISMATCH;
557 *next_offset = IVAL(dir_data, 0);
559 if (*next_offset > dir_data_length) {
560 return NT_STATUS_INFO_LENGTH_MISMATCH;
563 if (*next_offset != 0) {
564 /* Ensure we only read what in this record. */
565 dir_data_length = *next_offset;
568 if (dir_data_length < 105) {
569 return NT_STATUS_INFO_LENGTH_MISMATCH;
572 finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
573 finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
574 finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32);
575 finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
576 finfo->mode = CVAL(dir_data + 56, 0);
577 namelen = IVAL(dir_data + 60,0);
578 if (namelen > (dir_data_length - 104)) {
579 return NT_STATUS_INFO_LENGTH_MISMATCH;
581 slen = CVAL(dir_data + 68, 0);
582 if (slen > 24) {
583 return NT_STATUS_INFO_LENGTH_MISMATCH;
585 ret = pull_string_talloc(finfo,
586 dir_data,
587 FLAGS2_UNICODE_STRINGS,
588 &finfo->short_name,
589 dir_data + 70,
590 slen,
591 STR_UNICODE);
592 if (ret == (size_t)-1) {
593 /* Bad conversion. */
594 return NT_STATUS_INVALID_NETWORK_RESPONSE;
597 ret = pull_string_talloc(finfo,
598 dir_data,
599 FLAGS2_UNICODE_STRINGS,
600 &finfo->name,
601 dir_data + 104,
602 namelen,
603 STR_UNICODE);
604 if (ret == (size_t)-1) {
605 /* Bad conversion. */
606 return NT_STATUS_INVALID_NETWORK_RESPONSE;
608 return NT_STATUS_OK;
611 /*******************************************************************
612 Given a filename - get its directory name
613 ********************************************************************/
615 static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
616 const char *dir,
617 char **parent,
618 const char **name)
620 char *p;
621 ptrdiff_t len;
623 p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
625 if (p == NULL) {
626 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
627 return false;
629 if (name) {
630 *name = dir;
632 return true;
635 len = p-dir;
637 if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
638 return false;
640 (*parent)[len] = '\0';
642 if (name) {
643 *name = p+1;
645 return true;
648 /***************************************************************
649 Wrapper that allows SMB2 to list a directory.
650 Synchronous only.
651 ***************************************************************/
653 NTSTATUS cli_smb2_list(struct cli_state *cli,
654 const char *pathname,
655 uint16_t attribute,
656 NTSTATUS (*fn)(const char *,
657 struct file_info *,
658 const char *,
659 void *),
660 void *state)
662 NTSTATUS status;
663 uint16_t fnum = 0xffff;
664 char *parent_dir = NULL;
665 const char *mask = NULL;
666 struct smb2_hnd *ph = NULL;
667 bool processed_file = false;
668 TALLOC_CTX *frame = talloc_stackframe();
669 TALLOC_CTX *subframe = NULL;
670 bool mask_has_wild;
672 if (smbXcli_conn_has_async_calls(cli->conn)) {
674 * Can't use sync call while an async call is in flight
676 status = NT_STATUS_INVALID_PARAMETER;
677 goto fail;
680 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
681 status = NT_STATUS_INVALID_PARAMETER;
682 goto fail;
685 /* Get the directory name. */
686 if (!windows_parent_dirname(frame,
687 pathname,
688 &parent_dir,
689 &mask)) {
690 status = NT_STATUS_NO_MEMORY;
691 goto fail;
694 mask_has_wild = ms_has_wild(mask);
696 status = cli_smb2_create_fnum(cli,
697 parent_dir,
698 0, /* create_flags */
699 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
700 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
701 FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
702 FILE_OPEN, /* create_disposition */
703 FILE_DIRECTORY_FILE, /* create_options */
704 &fnum,
705 NULL);
707 if (!NT_STATUS_IS_OK(status)) {
708 goto fail;
711 status = map_fnum_to_smb2_handle(cli,
712 fnum,
713 &ph);
714 if (!NT_STATUS_IS_OK(status)) {
715 goto fail;
718 do {
719 uint8_t *dir_data = NULL;
720 uint32_t dir_data_length = 0;
721 uint32_t next_offset = 0;
722 subframe = talloc_stackframe();
724 status = smb2cli_query_directory(cli->conn,
725 cli->timeout,
726 cli->smb2.session,
727 cli->smb2.tcon,
728 SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
729 0, /* flags */
730 0, /* file_index */
731 ph->fid_persistent,
732 ph->fid_volatile,
733 mask,
734 0xffff,
735 subframe,
736 &dir_data,
737 &dir_data_length);
739 if (!NT_STATUS_IS_OK(status)) {
740 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
741 break;
743 goto fail;
746 do {
747 struct file_info *finfo = talloc_zero(subframe,
748 struct file_info);
750 if (finfo == NULL) {
751 status = NT_STATUS_NO_MEMORY;
752 goto fail;
755 status = parse_finfo_id_both_directory_info(dir_data,
756 dir_data_length,
757 finfo,
758 &next_offset);
760 if (!NT_STATUS_IS_OK(status)) {
761 goto fail;
764 if (dir_check_ftype((uint32_t)finfo->mode,
765 (uint32_t)attribute)) {
767 * Only process if attributes match.
768 * On SMB1 server does this, so on
769 * SMB2 we need to emulate in the
770 * client.
772 * https://bugzilla.samba.org/show_bug.cgi?id=10260
774 processed_file = true;
776 status = fn(cli->dfs_mountpoint,
777 finfo,
778 pathname,
779 state);
781 if (!NT_STATUS_IS_OK(status)) {
782 break;
786 TALLOC_FREE(finfo);
788 /* Move to next entry. */
789 if (next_offset) {
790 dir_data += next_offset;
791 dir_data_length -= next_offset;
793 } while (next_offset != 0);
795 TALLOC_FREE(subframe);
797 if (!mask_has_wild) {
799 * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
800 * when handed a non-wildcard path. Do it
801 * for the server (with a non-wildcard path
802 * there should only ever be one file returned.
804 status = STATUS_NO_MORE_FILES;
805 break;
808 } while (NT_STATUS_IS_OK(status));
810 if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
811 status = NT_STATUS_OK;
814 if (NT_STATUS_IS_OK(status) && !processed_file) {
816 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
817 * if no files match. Emulate this in the client.
819 status = NT_STATUS_NO_SUCH_FILE;
822 fail:
824 if (fnum != 0xffff) {
825 cli_smb2_close_fnum(cli, fnum);
827 TALLOC_FREE(subframe);
828 TALLOC_FREE(frame);
829 return status;
832 /***************************************************************
833 Wrapper that allows SMB2 to query a path info (basic level).
834 Synchronous only.
835 ***************************************************************/
837 NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
838 const char *name,
839 SMB_STRUCT_STAT *sbuf,
840 uint32_t *attributes)
842 NTSTATUS status;
843 struct smb_create_returns cr;
844 uint16_t fnum = 0xffff;
845 size_t namelen = strlen(name);
847 if (smbXcli_conn_has_async_calls(cli->conn)) {
849 * Can't use sync call while an async call is in flight
851 return NT_STATUS_INVALID_PARAMETER;
854 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
855 return NT_STATUS_INVALID_PARAMETER;
858 /* SMB2 is pickier about pathnames. Ensure it doesn't
859 end in a '\' */
860 if (namelen > 0 && name[namelen-1] == '\\') {
861 char *modname = talloc_strdup(talloc_tos(), name);
862 modname[namelen-1] = '\0';
863 name = modname;
866 /* This is commonly used as a 'cd'. Try qpathinfo on
867 a directory handle first. */
869 status = cli_smb2_create_fnum(cli,
870 name,
871 0, /* create_flags */
872 FILE_READ_ATTRIBUTES, /* desired_access */
873 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
874 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
875 FILE_OPEN, /* create_disposition */
876 FILE_DIRECTORY_FILE, /* create_options */
877 &fnum,
878 &cr);
880 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
881 /* Maybe a file ? */
882 status = cli_smb2_create_fnum(cli,
883 name,
884 0, /* create_flags */
885 FILE_READ_ATTRIBUTES, /* desired_access */
886 0, /* file attributes */
887 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
888 FILE_OPEN, /* create_disposition */
889 0, /* create_options */
890 &fnum,
891 &cr);
894 if (!NT_STATUS_IS_OK(status)) {
895 return status;
898 cli_smb2_close_fnum(cli, fnum);
900 ZERO_STRUCTP(sbuf);
902 sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
903 sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
904 sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
905 sbuf->st_ex_size = cr.end_of_file;
906 *attributes = cr.file_attributes;
908 return NT_STATUS_OK;
911 /***************************************************************
912 Helper function for pathname operations.
913 ***************************************************************/
915 static NTSTATUS get_fnum_from_path(struct cli_state *cli,
916 const char *name,
917 uint32_t desired_access,
918 uint16_t *pfnum)
920 NTSTATUS status;
921 size_t namelen = strlen(name);
922 TALLOC_CTX *frame = talloc_stackframe();
924 /* SMB2 is pickier about pathnames. Ensure it doesn't
925 end in a '\' */
926 if (namelen > 0 && name[namelen-1] == '\\') {
927 char *modname = talloc_strdup(frame, name);
928 if (modname == NULL) {
929 status = NT_STATUS_NO_MEMORY;
930 goto fail;
932 modname[namelen-1] = '\0';
933 name = modname;
936 /* Try to open a file handle first. */
937 status = cli_smb2_create_fnum(cli,
938 name,
939 0, /* create_flags */
940 desired_access,
941 0, /* file attributes */
942 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
943 FILE_OPEN, /* create_disposition */
944 0, /* create_options */
945 pfnum,
946 NULL);
948 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
949 status = cli_smb2_create_fnum(cli,
950 name,
951 0, /* create_flags */
952 desired_access,
953 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
954 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
955 FILE_OPEN, /* create_disposition */
956 FILE_DIRECTORY_FILE, /* create_options */
957 pfnum,
958 NULL);
961 fail:
963 TALLOC_FREE(frame);
964 return status;
967 /***************************************************************
968 Wrapper that allows SMB2 to query a path info (ALTNAME level).
969 Synchronous only.
970 ***************************************************************/
972 NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli,
973 const char *name,
974 fstring alt_name)
976 NTSTATUS status;
977 DATA_BLOB outbuf = data_blob_null;
978 uint16_t fnum = 0xffff;
979 struct smb2_hnd *ph = NULL;
980 uint32_t altnamelen = 0;
981 TALLOC_CTX *frame = talloc_stackframe();
983 if (smbXcli_conn_has_async_calls(cli->conn)) {
985 * Can't use sync call while an async call is in flight
987 status = NT_STATUS_INVALID_PARAMETER;
988 goto fail;
991 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
992 status = NT_STATUS_INVALID_PARAMETER;
993 goto fail;
996 status = get_fnum_from_path(cli,
997 name,
998 FILE_READ_ATTRIBUTES,
999 &fnum);
1001 if (!NT_STATUS_IS_OK(status)) {
1002 goto fail;
1005 status = map_fnum_to_smb2_handle(cli,
1006 fnum,
1007 &ph);
1008 if (!NT_STATUS_IS_OK(status)) {
1009 goto fail;
1012 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1013 level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */
1015 status = smb2cli_query_info(cli->conn,
1016 cli->timeout,
1017 cli->smb2.session,
1018 cli->smb2.tcon,
1019 1, /* in_info_type */
1020 (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */
1021 0xFFFF, /* in_max_output_length */
1022 NULL, /* in_input_buffer */
1023 0, /* in_additional_info */
1024 0, /* in_flags */
1025 ph->fid_persistent,
1026 ph->fid_volatile,
1027 frame,
1028 &outbuf);
1030 if (!NT_STATUS_IS_OK(status)) {
1031 goto fail;
1034 /* Parse the reply. */
1035 if (outbuf.length < 4) {
1036 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1037 goto fail;
1040 altnamelen = IVAL(outbuf.data, 0);
1041 if (altnamelen > outbuf.length - 4) {
1042 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1043 goto fail;
1046 if (altnamelen > 0) {
1047 size_t ret = 0;
1048 char *short_name = NULL;
1049 ret = pull_string_talloc(frame,
1050 outbuf.data,
1051 FLAGS2_UNICODE_STRINGS,
1052 &short_name,
1053 outbuf.data + 4,
1054 altnamelen,
1055 STR_UNICODE);
1056 if (ret == (size_t)-1) {
1057 /* Bad conversion. */
1058 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1059 goto fail;
1062 fstrcpy(alt_name, short_name);
1063 } else {
1064 alt_name[0] = '\0';
1067 status = NT_STATUS_OK;
1069 fail:
1071 if (fnum != 0xffff) {
1072 cli_smb2_close_fnum(cli, fnum);
1074 TALLOC_FREE(frame);
1075 return status;
1079 /***************************************************************
1080 Wrapper that allows SMB2 to query a fnum info (basic level).
1081 Synchronous only.
1082 ***************************************************************/
1084 NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli,
1085 uint16_t fnum,
1086 uint16_t *mode,
1087 off_t *size,
1088 struct timespec *create_time,
1089 struct timespec *access_time,
1090 struct timespec *write_time,
1091 struct timespec *change_time,
1092 SMB_INO_T *ino)
1094 NTSTATUS status;
1095 DATA_BLOB outbuf = data_blob_null;
1096 struct smb2_hnd *ph = NULL;
1097 TALLOC_CTX *frame = talloc_stackframe();
1099 if (smbXcli_conn_has_async_calls(cli->conn)) {
1101 * Can't use sync call while an async call is in flight
1103 status = NT_STATUS_INVALID_PARAMETER;
1104 goto fail;
1107 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1108 status = NT_STATUS_INVALID_PARAMETER;
1109 goto fail;
1112 status = map_fnum_to_smb2_handle(cli,
1113 fnum,
1114 &ph);
1115 if (!NT_STATUS_IS_OK(status)) {
1116 goto fail;
1119 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1120 level 0x12 (SMB2_FILE_ALL_INFORMATION). */
1122 status = smb2cli_query_info(cli->conn,
1123 cli->timeout,
1124 cli->smb2.session,
1125 cli->smb2.tcon,
1126 1, /* in_info_type */
1127 (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1128 0xFFFF, /* in_max_output_length */
1129 NULL, /* in_input_buffer */
1130 0, /* in_additional_info */
1131 0, /* in_flags */
1132 ph->fid_persistent,
1133 ph->fid_volatile,
1134 frame,
1135 &outbuf);
1136 if (!NT_STATUS_IS_OK(status)) {
1137 goto fail;
1140 /* Parse the reply. */
1141 if (outbuf.length < 0x60) {
1142 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1143 goto fail;
1146 if (create_time) {
1147 *create_time = interpret_long_date((const char *)outbuf.data + 0x0);
1149 if (access_time) {
1150 *access_time = interpret_long_date((const char *)outbuf.data + 0x8);
1152 if (write_time) {
1153 *write_time = interpret_long_date((const char *)outbuf.data + 0x10);
1155 if (change_time) {
1156 *change_time = interpret_long_date((const char *)outbuf.data + 0x18);
1158 if (mode) {
1159 uint32_t attr = IVAL(outbuf.data, 0x20);
1160 *mode = (uint16_t)attr;
1162 if (size) {
1163 uint64_t file_size = BVAL(outbuf.data, 0x30);
1164 *size = (off_t)file_size;
1166 if (ino) {
1167 uint64_t file_index = BVAL(outbuf.data, 0x40);
1168 *ino = (SMB_INO_T)file_index;
1171 fail:
1173 TALLOC_FREE(frame);
1174 return status;
1177 /***************************************************************
1178 Wrapper that allows SMB2 to query an fnum.
1179 Implement on top of cli_smb2_qfileinfo_basic().
1180 Synchronous only.
1181 ***************************************************************/
1183 NTSTATUS cli_smb2_getattrE(struct cli_state *cli,
1184 uint16_t fnum,
1185 uint16_t *attr,
1186 off_t *size,
1187 time_t *change_time,
1188 time_t *access_time,
1189 time_t *write_time)
1191 struct timespec access_time_ts;
1192 struct timespec write_time_ts;
1193 struct timespec change_time_ts;
1194 NTSTATUS status = cli_smb2_qfileinfo_basic(cli,
1195 fnum,
1196 attr,
1197 size,
1198 NULL,
1199 &access_time_ts,
1200 &write_time_ts,
1201 &change_time_ts,
1202 NULL);
1204 if (!NT_STATUS_IS_OK(status)) {
1205 return status;
1208 if (change_time) {
1209 *change_time = change_time_ts.tv_sec;
1211 if (access_time) {
1212 *access_time = access_time_ts.tv_sec;
1214 if (write_time) {
1215 *write_time = write_time_ts.tv_sec;
1217 return NT_STATUS_OK;
1220 /***************************************************************
1221 Wrapper that allows SMB2 to get pathname attributes.
1222 Synchronous only.
1223 ***************************************************************/
1225 NTSTATUS cli_smb2_getatr(struct cli_state *cli,
1226 const char *name,
1227 uint16_t *attr,
1228 off_t *size,
1229 time_t *write_time)
1231 NTSTATUS status;
1232 uint16_t fnum = 0xffff;
1233 struct smb2_hnd *ph = NULL;
1234 TALLOC_CTX *frame = talloc_stackframe();
1236 if (smbXcli_conn_has_async_calls(cli->conn)) {
1238 * Can't use sync call while an async call is in flight
1240 status = NT_STATUS_INVALID_PARAMETER;
1241 goto fail;
1244 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1245 status = NT_STATUS_INVALID_PARAMETER;
1246 goto fail;
1249 status = get_fnum_from_path(cli,
1250 name,
1251 FILE_READ_ATTRIBUTES,
1252 &fnum);
1254 if (!NT_STATUS_IS_OK(status)) {
1255 goto fail;
1258 status = map_fnum_to_smb2_handle(cli,
1259 fnum,
1260 &ph);
1261 if (!NT_STATUS_IS_OK(status)) {
1262 goto fail;
1264 status = cli_smb2_getattrE(cli,
1265 fnum,
1266 attr,
1267 size,
1268 NULL,
1269 NULL,
1270 write_time);
1271 if (!NT_STATUS_IS_OK(status)) {
1272 goto fail;
1275 fail:
1277 if (fnum != 0xffff) {
1278 cli_smb2_close_fnum(cli, fnum);
1281 TALLOC_FREE(frame);
1282 return status;
1285 /***************************************************************
1286 Wrapper that allows SMB2 to query a pathname info (basic level).
1287 Implement on top of cli_smb2_qfileinfo_basic().
1288 Synchronous only.
1289 ***************************************************************/
1291 NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli,
1292 const char *name,
1293 struct timespec *create_time,
1294 struct timespec *access_time,
1295 struct timespec *write_time,
1296 struct timespec *change_time,
1297 off_t *size,
1298 uint16_t *mode,
1299 SMB_INO_T *ino)
1301 NTSTATUS status;
1302 struct smb2_hnd *ph = NULL;
1303 uint16_t fnum = 0xffff;
1304 TALLOC_CTX *frame = talloc_stackframe();
1306 if (smbXcli_conn_has_async_calls(cli->conn)) {
1308 * Can't use sync call while an async call is in flight
1310 status = NT_STATUS_INVALID_PARAMETER;
1311 goto fail;
1314 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1315 status = NT_STATUS_INVALID_PARAMETER;
1316 goto fail;
1319 status = get_fnum_from_path(cli,
1320 name,
1321 FILE_READ_ATTRIBUTES,
1322 &fnum);
1324 if (!NT_STATUS_IS_OK(status)) {
1325 goto fail;
1328 status = map_fnum_to_smb2_handle(cli,
1329 fnum,
1330 &ph);
1331 if (!NT_STATUS_IS_OK(status)) {
1332 goto fail;
1335 status = cli_smb2_qfileinfo_basic(cli,
1336 fnum,
1337 mode,
1338 size,
1339 create_time,
1340 access_time,
1341 write_time,
1342 change_time,
1343 ino);
1345 fail:
1347 if (fnum != 0xffff) {
1348 cli_smb2_close_fnum(cli, fnum);
1351 TALLOC_FREE(frame);
1352 return status;
1355 /***************************************************************
1356 Wrapper that allows SMB2 to query pathname streams.
1357 Synchronous only.
1358 ***************************************************************/
1360 NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli,
1361 const char *name,
1362 TALLOC_CTX *mem_ctx,
1363 unsigned int *pnum_streams,
1364 struct stream_struct **pstreams)
1366 NTSTATUS status;
1367 struct smb2_hnd *ph = NULL;
1368 uint16_t fnum = 0xffff;
1369 DATA_BLOB outbuf = data_blob_null;
1370 TALLOC_CTX *frame = talloc_stackframe();
1372 if (smbXcli_conn_has_async_calls(cli->conn)) {
1374 * Can't use sync call while an async call is in flight
1376 status = NT_STATUS_INVALID_PARAMETER;
1377 goto fail;
1380 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1381 status = NT_STATUS_INVALID_PARAMETER;
1382 goto fail;
1385 status = get_fnum_from_path(cli,
1386 name,
1387 FILE_READ_ATTRIBUTES,
1388 &fnum);
1390 if (!NT_STATUS_IS_OK(status)) {
1391 goto fail;
1394 status = map_fnum_to_smb2_handle(cli,
1395 fnum,
1396 &ph);
1397 if (!NT_STATUS_IS_OK(status)) {
1398 goto fail;
1401 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
1402 level 22 (SMB2_FILE_STREAM_INFORMATION). */
1404 status = smb2cli_query_info(cli->conn,
1405 cli->timeout,
1406 cli->smb2.session,
1407 cli->smb2.tcon,
1408 1, /* in_info_type */
1409 (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */
1410 0xFFFF, /* in_max_output_length */
1411 NULL, /* in_input_buffer */
1412 0, /* in_additional_info */
1413 0, /* in_flags */
1414 ph->fid_persistent,
1415 ph->fid_volatile,
1416 frame,
1417 &outbuf);
1419 if (!NT_STATUS_IS_OK(status)) {
1420 goto fail;
1423 /* Parse the reply. */
1424 if (!parse_streams_blob(mem_ctx,
1425 outbuf.data,
1426 outbuf.length,
1427 pnum_streams,
1428 pstreams)) {
1429 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1430 goto fail;
1433 fail:
1435 if (fnum != 0xffff) {
1436 cli_smb2_close_fnum(cli, fnum);
1439 TALLOC_FREE(frame);
1440 return status;
1443 /***************************************************************
1444 Wrapper that allows SMB2 to set pathname attributes.
1445 Synchronous only.
1446 ***************************************************************/
1448 NTSTATUS cli_smb2_setatr(struct cli_state *cli,
1449 const char *name,
1450 uint16_t attr,
1451 time_t mtime)
1453 NTSTATUS status;
1454 uint16_t fnum = 0xffff;
1455 struct smb2_hnd *ph = NULL;
1456 uint8_t inbuf_store[40];
1457 DATA_BLOB inbuf = data_blob_null;
1458 TALLOC_CTX *frame = talloc_stackframe();
1460 if (smbXcli_conn_has_async_calls(cli->conn)) {
1462 * Can't use sync call while an async call is in flight
1464 status = NT_STATUS_INVALID_PARAMETER;
1465 goto fail;
1468 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1469 status = NT_STATUS_INVALID_PARAMETER;
1470 goto fail;
1473 status = get_fnum_from_path(cli,
1474 name,
1475 FILE_WRITE_ATTRIBUTES,
1476 &fnum);
1478 if (!NT_STATUS_IS_OK(status)) {
1479 goto fail;
1482 status = map_fnum_to_smb2_handle(cli,
1483 fnum,
1484 &ph);
1485 if (!NT_STATUS_IS_OK(status)) {
1486 goto fail;
1489 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1490 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1492 inbuf.data = inbuf_store;
1493 inbuf.length = sizeof(inbuf_store);
1494 data_blob_clear(&inbuf);
1496 SSVAL(inbuf.data, 32, attr);
1497 if (mtime != 0) {
1498 put_long_date((char *)inbuf.data + 16,mtime);
1500 /* Set all the other times to -1. */
1501 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1502 SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
1503 SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
1505 status = smb2cli_set_info(cli->conn,
1506 cli->timeout,
1507 cli->smb2.session,
1508 cli->smb2.tcon,
1509 1, /* in_info_type */
1510 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1511 &inbuf, /* in_input_buffer */
1512 0, /* in_additional_info */
1513 ph->fid_persistent,
1514 ph->fid_volatile);
1515 fail:
1517 if (fnum != 0xffff) {
1518 cli_smb2_close_fnum(cli, fnum);
1521 TALLOC_FREE(frame);
1522 return status;
1525 /***************************************************************
1526 Wrapper that allows SMB2 to set file handle times.
1527 Synchronous only.
1528 ***************************************************************/
1530 NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
1531 uint16_t fnum,
1532 time_t change_time,
1533 time_t access_time,
1534 time_t write_time)
1536 NTSTATUS status;
1537 struct smb2_hnd *ph = NULL;
1538 uint8_t inbuf_store[40];
1539 DATA_BLOB inbuf = data_blob_null;
1541 if (smbXcli_conn_has_async_calls(cli->conn)) {
1543 * Can't use sync call while an async call is in flight
1545 return NT_STATUS_INVALID_PARAMETER;
1548 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1549 return NT_STATUS_INVALID_PARAMETER;
1552 status = map_fnum_to_smb2_handle(cli,
1553 fnum,
1554 &ph);
1555 if (!NT_STATUS_IS_OK(status)) {
1556 return status;
1559 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
1560 level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
1562 inbuf.data = inbuf_store;
1563 inbuf.length = sizeof(inbuf_store);
1564 data_blob_clear(&inbuf);
1566 SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
1567 if (change_time != 0) {
1568 put_long_date((char *)inbuf.data + 24, change_time);
1570 if (access_time != 0) {
1571 put_long_date((char *)inbuf.data + 8, access_time);
1573 if (write_time != 0) {
1574 put_long_date((char *)inbuf.data + 16, write_time);
1577 return smb2cli_set_info(cli->conn,
1578 cli->timeout,
1579 cli->smb2.session,
1580 cli->smb2.tcon,
1581 1, /* in_info_type */
1582 SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */
1583 &inbuf, /* in_input_buffer */
1584 0, /* in_additional_info */
1585 ph->fid_persistent,
1586 ph->fid_volatile);
1589 /***************************************************************
1590 Wrapper that allows SMB2 to query disk attributes (size).
1591 Synchronous only.
1592 ***************************************************************/
1594 NTSTATUS cli_smb2_dskattr(struct cli_state *cli, uint64_t *bsize, uint64_t *total, uint64_t *avail)
1596 NTSTATUS status;
1597 uint16_t fnum = 0xffff;
1598 DATA_BLOB outbuf = data_blob_null;
1599 struct smb2_hnd *ph = NULL;
1600 uint32_t sectors_per_unit = 0;
1601 uint32_t bytes_per_sector = 0;
1602 uint64_t total_size = 0;
1603 uint64_t size_free = 0;
1604 TALLOC_CTX *frame = talloc_stackframe();
1606 if (smbXcli_conn_has_async_calls(cli->conn)) {
1608 * Can't use sync call while an async call is in flight
1610 status = NT_STATUS_INVALID_PARAMETER;
1611 goto fail;
1614 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1615 status = NT_STATUS_INVALID_PARAMETER;
1616 goto fail;
1619 /* First open the top level directory. */
1620 status = cli_smb2_create_fnum(cli,
1622 0, /* create_flags */
1623 FILE_READ_ATTRIBUTES, /* desired_access */
1624 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
1625 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
1626 FILE_OPEN, /* create_disposition */
1627 FILE_DIRECTORY_FILE, /* create_options */
1628 &fnum,
1629 NULL);
1631 if (!NT_STATUS_IS_OK(status)) {
1632 goto fail;
1635 status = map_fnum_to_smb2_handle(cli,
1636 fnum,
1637 &ph);
1638 if (!NT_STATUS_IS_OK(status)) {
1639 goto fail;
1642 /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
1643 level 3 (SMB_FS_SIZE_INFORMATION). */
1645 status = smb2cli_query_info(cli->conn,
1646 cli->timeout,
1647 cli->smb2.session,
1648 cli->smb2.tcon,
1649 2, /* in_info_type */
1650 3, /* in_file_info_class */
1651 0xFFFF, /* in_max_output_length */
1652 NULL, /* in_input_buffer */
1653 0, /* in_additional_info */
1654 0, /* in_flags */
1655 ph->fid_persistent,
1656 ph->fid_volatile,
1657 frame,
1658 &outbuf);
1659 if (!NT_STATUS_IS_OK(status)) {
1660 goto fail;
1663 /* Parse the reply. */
1664 if (outbuf.length != 24) {
1665 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
1666 goto fail;
1669 total_size = BVAL(outbuf.data, 0);
1670 size_free = BVAL(outbuf.data, 8);
1671 sectors_per_unit = IVAL(outbuf.data, 16);
1672 bytes_per_sector = IVAL(outbuf.data, 20);
1674 if (bsize) {
1675 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
1677 if (total) {
1678 *total = total_size;
1680 if (avail) {
1681 *avail = size_free;
1684 status = NT_STATUS_OK;
1686 fail:
1688 if (fnum != 0xffff) {
1689 cli_smb2_close_fnum(cli, fnum);
1692 TALLOC_FREE(frame);
1693 return status;
1696 /***************************************************************
1697 Wrapper that allows SMB2 to query a security descriptor.
1698 Synchronous only.
1699 ***************************************************************/
1701 NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
1702 uint16_t fnum,
1703 uint32_t sec_info,
1704 TALLOC_CTX *mem_ctx,
1705 struct security_descriptor **ppsd)
1707 NTSTATUS status;
1708 DATA_BLOB outbuf = data_blob_null;
1709 struct smb2_hnd *ph = NULL;
1710 struct security_descriptor *lsd = NULL;
1711 TALLOC_CTX *frame = talloc_stackframe();
1713 if (smbXcli_conn_has_async_calls(cli->conn)) {
1715 * Can't use sync call while an async call is in flight
1717 status = NT_STATUS_INVALID_PARAMETER;
1718 goto fail;
1721 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1722 status = NT_STATUS_INVALID_PARAMETER;
1723 goto fail;
1726 status = map_fnum_to_smb2_handle(cli,
1727 fnum,
1728 &ph);
1729 if (!NT_STATUS_IS_OK(status)) {
1730 goto fail;
1733 /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */
1735 status = smb2cli_query_info(cli->conn,
1736 cli->timeout,
1737 cli->smb2.session,
1738 cli->smb2.tcon,
1739 3, /* in_info_type */
1740 0, /* in_file_info_class */
1741 0xFFFF, /* in_max_output_length */
1742 NULL, /* in_input_buffer */
1743 sec_info, /* in_additional_info */
1744 0, /* in_flags */
1745 ph->fid_persistent,
1746 ph->fid_volatile,
1747 frame,
1748 &outbuf);
1750 if (!NT_STATUS_IS_OK(status)) {
1751 goto fail;
1754 /* Parse the reply. */
1755 status = unmarshall_sec_desc(mem_ctx,
1756 outbuf.data,
1757 outbuf.length,
1758 &lsd);
1760 if (!NT_STATUS_IS_OK(status)) {
1761 goto fail;
1764 if (ppsd != NULL) {
1765 *ppsd = lsd;
1766 } else {
1767 TALLOC_FREE(lsd);
1770 fail:
1772 TALLOC_FREE(frame);
1773 return status;
1776 /***************************************************************
1777 Wrapper that allows SMB2 to set a security descriptor.
1778 Synchronous only.
1779 ***************************************************************/
1781 NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli,
1782 uint16_t fnum,
1783 uint32_t sec_info,
1784 const struct security_descriptor *sd)
1786 NTSTATUS status;
1787 DATA_BLOB inbuf = data_blob_null;
1788 struct smb2_hnd *ph = NULL;
1789 TALLOC_CTX *frame = talloc_stackframe();
1791 if (smbXcli_conn_has_async_calls(cli->conn)) {
1793 * Can't use sync call while an async call is in flight
1795 status = NT_STATUS_INVALID_PARAMETER;
1796 goto fail;
1799 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1800 status = NT_STATUS_INVALID_PARAMETER;
1801 goto fail;
1804 status = map_fnum_to_smb2_handle(cli,
1805 fnum,
1806 &ph);
1807 if (!NT_STATUS_IS_OK(status)) {
1808 goto fail;
1811 status = marshall_sec_desc(frame,
1813 &inbuf.data,
1814 &inbuf.length);
1816 if (!NT_STATUS_IS_OK(status)) {
1817 goto fail;
1820 /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */
1822 status = smb2cli_set_info(cli->conn,
1823 cli->timeout,
1824 cli->smb2.session,
1825 cli->smb2.tcon,
1826 3, /* in_info_type */
1827 0, /* in_file_info_class */
1828 &inbuf, /* in_input_buffer */
1829 sec_info, /* in_additional_info */
1830 ph->fid_persistent,
1831 ph->fid_volatile);
1833 fail:
1835 TALLOC_FREE(frame);
1836 return status;
1839 /***************************************************************
1840 Wrapper that allows SMB2 to rename a file.
1841 Synchronous only.
1842 ***************************************************************/
1844 NTSTATUS cli_smb2_rename(struct cli_state *cli,
1845 const char *fname_src,
1846 const char *fname_dst)
1848 NTSTATUS status;
1849 DATA_BLOB inbuf = data_blob_null;
1850 uint16_t fnum = 0xffff;
1851 struct smb2_hnd *ph = NULL;
1852 smb_ucs2_t *converted_str = NULL;
1853 size_t converted_size_bytes = 0;
1854 size_t namelen = 0;
1855 TALLOC_CTX *frame = talloc_stackframe();
1857 if (smbXcli_conn_has_async_calls(cli->conn)) {
1859 * Can't use sync call while an async call is in flight
1861 status = NT_STATUS_INVALID_PARAMETER;
1862 goto fail;
1865 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1866 status = NT_STATUS_INVALID_PARAMETER;
1867 goto fail;
1870 status = get_fnum_from_path(cli,
1871 fname_src,
1872 DELETE_ACCESS,
1873 &fnum);
1875 if (!NT_STATUS_IS_OK(status)) {
1876 goto fail;
1879 status = map_fnum_to_smb2_handle(cli,
1880 fnum,
1881 &ph);
1882 if (!NT_STATUS_IS_OK(status)) {
1883 goto fail;
1886 /* SMB2 is pickier about pathnames. Ensure it doesn't
1887 start in a '\' */
1888 if (*fname_dst == '\\') {
1889 fname_dst++;
1892 /* SMB2 is pickier about pathnames. Ensure it doesn't
1893 end in a '\' */
1894 namelen = strlen(fname_dst);
1895 if (namelen > 0 && fname_dst[namelen-1] == '\\') {
1896 char *modname = talloc_strdup(frame, fname_dst);
1897 modname[namelen-1] = '\0';
1898 fname_dst = modname;
1901 if (!push_ucs2_talloc(frame,
1902 &converted_str,
1903 fname_dst,
1904 &converted_size_bytes)) {
1905 status = NT_STATUS_INVALID_PARAMETER;
1906 goto fail;
1909 /* W2K8 insists the dest name is not null
1910 terminated. Remove the last 2 zero bytes
1911 and reduce the name length. */
1913 if (converted_size_bytes < 2) {
1914 status = NT_STATUS_INVALID_PARAMETER;
1915 goto fail;
1917 converted_size_bytes -= 2;
1919 inbuf = data_blob_talloc_zero(frame,
1920 20 + converted_size_bytes);
1921 if (inbuf.data == NULL) {
1922 status = NT_STATUS_NO_MEMORY;
1923 goto fail;
1926 SIVAL(inbuf.data, 16, converted_size_bytes);
1927 memcpy(inbuf.data + 20, converted_str, converted_size_bytes);
1929 /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
1930 level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
1932 status = smb2cli_set_info(cli->conn,
1933 cli->timeout,
1934 cli->smb2.session,
1935 cli->smb2.tcon,
1936 1, /* in_info_type */
1937 SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */
1938 &inbuf, /* in_input_buffer */
1939 0, /* in_additional_info */
1940 ph->fid_persistent,
1941 ph->fid_volatile);
1943 fail:
1945 if (fnum != 0xffff) {
1946 cli_smb2_close_fnum(cli, fnum);
1949 TALLOC_FREE(frame);
1950 return status;
1953 /***************************************************************
1954 Wrapper that allows SMB2 to set an EA on a fnum.
1955 Synchronous only.
1956 ***************************************************************/
1958 NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
1959 uint16_t fnum,
1960 const char *ea_name,
1961 const char *ea_val,
1962 size_t ea_len)
1964 NTSTATUS status;
1965 DATA_BLOB inbuf = data_blob_null;
1966 size_t bloblen = 0;
1967 char *ea_name_ascii = NULL;
1968 size_t namelen = 0;
1969 struct smb2_hnd *ph = NULL;
1970 TALLOC_CTX *frame = talloc_stackframe();
1972 if (smbXcli_conn_has_async_calls(cli->conn)) {
1974 * Can't use sync call while an async call is in flight
1976 status = NT_STATUS_INVALID_PARAMETER;
1977 goto fail;
1980 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
1981 status = NT_STATUS_INVALID_PARAMETER;
1982 goto fail;
1985 status = map_fnum_to_smb2_handle(cli,
1986 fnum,
1987 &ph);
1988 if (!NT_STATUS_IS_OK(status)) {
1989 goto fail;
1992 /* Marshall the SMB2 EA data. */
1993 if (ea_len > 0xFFFF) {
1994 status = NT_STATUS_INVALID_PARAMETER;
1995 goto fail;
1998 if (!push_ascii_talloc(frame,
1999 &ea_name_ascii,
2000 ea_name,
2001 &namelen)) {
2002 status = NT_STATUS_INVALID_PARAMETER;
2003 goto fail;
2006 if (namelen < 2 || namelen > 0xFF) {
2007 status = NT_STATUS_INVALID_PARAMETER;
2008 goto fail;
2011 bloblen = 8 + ea_len + namelen;
2012 /* Round up to a 4 byte boundary. */
2013 bloblen = ((bloblen + 3)&~3);
2015 inbuf = data_blob_talloc_zero(frame, bloblen);
2016 if (inbuf.data == NULL) {
2017 status = NT_STATUS_NO_MEMORY;
2018 goto fail;
2020 /* namelen doesn't include the NULL byte. */
2021 SCVAL(inbuf.data, 5, namelen - 1);
2022 SSVAL(inbuf.data, 6, ea_len);
2023 memcpy(inbuf.data + 8, ea_name_ascii, namelen);
2024 memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
2026 /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
2027 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2029 status = smb2cli_set_info(cli->conn,
2030 cli->timeout,
2031 cli->smb2.session,
2032 cli->smb2.tcon,
2033 1, /* in_info_type */
2034 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2035 &inbuf, /* in_input_buffer */
2036 0, /* in_additional_info */
2037 ph->fid_persistent,
2038 ph->fid_volatile);
2040 fail:
2042 TALLOC_FREE(frame);
2043 return status;
2046 /***************************************************************
2047 Wrapper that allows SMB2 to set an EA on a pathname.
2048 Synchronous only.
2049 ***************************************************************/
2051 NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
2052 const char *name,
2053 const char *ea_name,
2054 const char *ea_val,
2055 size_t ea_len)
2057 NTSTATUS status;
2058 uint16_t fnum = 0xffff;
2060 if (smbXcli_conn_has_async_calls(cli->conn)) {
2062 * Can't use sync call while an async call is in flight
2064 status = NT_STATUS_INVALID_PARAMETER;
2065 goto fail;
2068 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2069 status = NT_STATUS_INVALID_PARAMETER;
2070 goto fail;
2073 status = get_fnum_from_path(cli,
2074 name,
2075 FILE_WRITE_EA,
2076 &fnum);
2078 if (!NT_STATUS_IS_OK(status)) {
2079 goto fail;
2082 status = cli_set_ea_fnum(cli,
2083 fnum,
2084 ea_name,
2085 ea_val,
2086 ea_len);
2087 if (!NT_STATUS_IS_OK(status)) {
2088 goto fail;
2091 fail:
2093 if (fnum != 0xffff) {
2094 cli_smb2_close_fnum(cli, fnum);
2097 return status;
2100 /***************************************************************
2101 Wrapper that allows SMB2 to get an EA list on a pathname.
2102 Synchronous only.
2103 ***************************************************************/
2105 NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
2106 const char *name,
2107 TALLOC_CTX *ctx,
2108 size_t *pnum_eas,
2109 struct ea_struct **pea_array)
2111 NTSTATUS status;
2112 uint16_t fnum = 0xffff;
2113 DATA_BLOB outbuf = data_blob_null;
2114 struct smb2_hnd *ph = NULL;
2115 struct ea_list *ea_list = NULL;
2116 struct ea_list *eal = NULL;
2117 size_t ea_count = 0;
2118 TALLOC_CTX *frame = talloc_stackframe();
2120 *pnum_eas = 0;
2121 *pea_array = NULL;
2123 if (smbXcli_conn_has_async_calls(cli->conn)) {
2125 * Can't use sync call while an async call is in flight
2127 status = NT_STATUS_INVALID_PARAMETER;
2128 goto fail;
2131 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
2132 status = NT_STATUS_INVALID_PARAMETER;
2133 goto fail;
2136 status = get_fnum_from_path(cli,
2137 name,
2138 FILE_READ_EA,
2139 &fnum);
2141 if (!NT_STATUS_IS_OK(status)) {
2142 goto fail;
2145 status = map_fnum_to_smb2_handle(cli,
2146 fnum,
2147 &ph);
2148 if (!NT_STATUS_IS_OK(status)) {
2149 goto fail;
2152 /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
2153 level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
2155 status = smb2cli_query_info(cli->conn,
2156 cli->timeout,
2157 cli->smb2.session,
2158 cli->smb2.tcon,
2159 1, /* in_info_type */
2160 SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */
2161 0xFFFF, /* in_max_output_length */
2162 NULL, /* in_input_buffer */
2163 0, /* in_additional_info */
2164 0, /* in_flags */
2165 ph->fid_persistent,
2166 ph->fid_volatile,
2167 frame,
2168 &outbuf);
2170 if (!NT_STATUS_IS_OK(status)) {
2171 goto fail;
2174 /* Parse the reply. */
2175 ea_list = read_nttrans_ea_list(ctx,
2176 (const char *)outbuf.data,
2177 outbuf.length);
2178 if (ea_list == NULL) {
2179 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2180 goto fail;
2183 /* Convert to an array. */
2184 for (eal = ea_list; eal; eal = eal->next) {
2185 ea_count++;
2188 if (ea_count) {
2189 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
2190 if (*pea_array == NULL) {
2191 status = NT_STATUS_NO_MEMORY;
2192 goto fail;
2194 ea_count = 0;
2195 for (eal = ea_list; eal; eal = eal->next) {
2196 (*pea_array)[ea_count++] = ea_list->ea;
2198 *pnum_eas = ea_count;
2201 fail:
2203 if (fnum != 0xffff) {
2204 cli_smb2_close_fnum(cli, fnum);
2207 TALLOC_FREE(frame);
2208 return status;
2211 struct cli_smb2_read_state {
2212 struct tevent_context *ev;
2213 struct cli_state *cli;
2214 struct smb2_hnd *ph;
2215 uint64_t start_offset;
2216 uint32_t size;
2217 uint32_t received;
2218 uint8_t *buf;
2221 static void cli_smb2_read_done(struct tevent_req *subreq);
2223 struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
2224 struct tevent_context *ev,
2225 struct cli_state *cli,
2226 uint16_t fnum,
2227 off_t offset,
2228 size_t size)
2230 NTSTATUS status;
2231 struct tevent_req *req, *subreq;
2232 struct cli_smb2_read_state *state;
2234 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
2235 if (req == NULL) {
2236 return NULL;
2238 state->ev = ev;
2239 state->cli = cli;
2240 state->start_offset = (uint64_t)offset;
2241 state->size = (uint32_t)size;
2242 state->received = 0;
2243 state->buf = NULL;
2245 status = map_fnum_to_smb2_handle(cli,
2246 fnum,
2247 &state->ph);
2248 if (tevent_req_nterror(req, status)) {
2249 return tevent_req_post(req, ev);
2252 subreq = smb2cli_read_send(state,
2253 state->ev,
2254 state->cli->conn,
2255 state->cli->timeout,
2256 state->cli->smb2.session,
2257 state->cli->smb2.tcon,
2258 state->size,
2259 state->start_offset,
2260 state->ph->fid_persistent,
2261 state->ph->fid_volatile,
2262 0, /* minimum_count */
2263 0); /* remaining_bytes */
2265 if (tevent_req_nomem(subreq, req)) {
2266 return tevent_req_post(req, ev);
2268 tevent_req_set_callback(subreq, cli_smb2_read_done, req);
2269 return req;
2272 static void cli_smb2_read_done(struct tevent_req *subreq)
2274 struct tevent_req *req = tevent_req_callback_data(
2275 subreq, struct tevent_req);
2276 struct cli_smb2_read_state *state = tevent_req_data(
2277 req, struct cli_smb2_read_state);
2278 NTSTATUS status;
2280 status = smb2cli_read_recv(subreq, state,
2281 &state->buf, &state->received);
2282 if (tevent_req_nterror(req, status)) {
2283 return;
2286 if (state->received > state->size) {
2287 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2288 return;
2291 tevent_req_done(req);
2294 NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
2295 ssize_t *received,
2296 uint8_t **rcvbuf)
2298 NTSTATUS status;
2299 struct cli_smb2_read_state *state = tevent_req_data(
2300 req, struct cli_smb2_read_state);
2302 if (tevent_req_is_nterror(req, &status)) {
2303 return status;
2306 * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
2307 * better make sure that you copy it away before you talloc_free(req).
2308 * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
2310 *received = (ssize_t)state->received;
2311 *rcvbuf = state->buf;
2312 return NT_STATUS_OK;
2315 struct cli_smb2_write_state {
2316 struct tevent_context *ev;
2317 struct cli_state *cli;
2318 struct smb2_hnd *ph;
2319 uint32_t flags;
2320 const uint8_t *buf;
2321 uint64_t offset;
2322 uint32_t size;
2323 uint32_t written;
2326 static void cli_smb2_write_written(struct tevent_req *req);
2328 struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
2329 struct tevent_context *ev,
2330 struct cli_state *cli,
2331 uint16_t fnum,
2332 uint16_t mode,
2333 const uint8_t *buf,
2334 off_t offset,
2335 size_t size)
2337 NTSTATUS status;
2338 struct tevent_req *req, *subreq = NULL;
2339 struct cli_smb2_write_state *state = NULL;
2341 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
2342 if (req == NULL) {
2343 return NULL;
2345 state->ev = ev;
2346 state->cli = cli;
2347 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2348 state->flags = (uint32_t)mode;
2349 state->buf = buf;
2350 state->offset = (uint64_t)offset;
2351 state->size = (uint32_t)size;
2352 state->written = 0;
2354 status = map_fnum_to_smb2_handle(cli,
2355 fnum,
2356 &state->ph);
2357 if (tevent_req_nterror(req, status)) {
2358 return tevent_req_post(req, ev);
2361 subreq = smb2cli_write_send(state,
2362 state->ev,
2363 state->cli->conn,
2364 state->cli->timeout,
2365 state->cli->smb2.session,
2366 state->cli->smb2.tcon,
2367 state->size,
2368 state->offset,
2369 state->ph->fid_persistent,
2370 state->ph->fid_volatile,
2371 0, /* remaining_bytes */
2372 state->flags, /* flags */
2373 state->buf);
2375 if (tevent_req_nomem(subreq, req)) {
2376 return tevent_req_post(req, ev);
2378 tevent_req_set_callback(subreq, cli_smb2_write_written, req);
2379 return req;
2382 static void cli_smb2_write_written(struct tevent_req *subreq)
2384 struct tevent_req *req = tevent_req_callback_data(
2385 subreq, struct tevent_req);
2386 struct cli_smb2_write_state *state = tevent_req_data(
2387 req, struct cli_smb2_write_state);
2388 NTSTATUS status;
2389 uint32_t written;
2391 status = smb2cli_write_recv(subreq, &written);
2392 TALLOC_FREE(subreq);
2393 if (tevent_req_nterror(req, status)) {
2394 return;
2397 state->written = written;
2399 tevent_req_done(req);
2402 NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
2403 size_t *pwritten)
2405 struct cli_smb2_write_state *state = tevent_req_data(
2406 req, struct cli_smb2_write_state);
2407 NTSTATUS status;
2409 if (tevent_req_is_nterror(req, &status)) {
2410 tevent_req_received(req);
2411 return status;
2414 if (pwritten != NULL) {
2415 *pwritten = (size_t)state->written;
2417 tevent_req_received(req);
2418 return NT_STATUS_OK;
2421 /***************************************************************
2422 Wrapper that allows SMB2 async write using an fnum.
2423 This is mostly cut-and-paste from Volker's code inside
2424 source3/libsmb/clireadwrite.c, adapted for SMB2.
2426 Done this way so I can reuse all the logic inside cli_push()
2427 for free :-).
2428 ***************************************************************/
2430 struct cli_smb2_writeall_state {
2431 struct tevent_context *ev;
2432 struct cli_state *cli;
2433 struct smb2_hnd *ph;
2434 uint32_t flags;
2435 const uint8_t *buf;
2436 uint64_t offset;
2437 uint32_t size;
2438 uint32_t written;
2441 static void cli_smb2_writeall_written(struct tevent_req *req);
2443 struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
2444 struct tevent_context *ev,
2445 struct cli_state *cli,
2446 uint16_t fnum,
2447 uint16_t mode,
2448 const uint8_t *buf,
2449 off_t offset,
2450 size_t size)
2452 NTSTATUS status;
2453 struct tevent_req *req, *subreq = NULL;
2454 struct cli_smb2_writeall_state *state = NULL;
2455 uint32_t to_write;
2456 uint32_t max_size;
2457 bool ok;
2459 req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
2460 if (req == NULL) {
2461 return NULL;
2463 state->ev = ev;
2464 state->cli = cli;
2465 /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
2466 state->flags = (uint32_t)mode;
2467 state->buf = buf;
2468 state->offset = (uint64_t)offset;
2469 state->size = (uint32_t)size;
2470 state->written = 0;
2472 status = map_fnum_to_smb2_handle(cli,
2473 fnum,
2474 &state->ph);
2475 if (tevent_req_nterror(req, status)) {
2476 return tevent_req_post(req, ev);
2479 to_write = state->size;
2480 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2481 to_write = MIN(max_size, to_write);
2482 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2483 if (ok) {
2484 to_write = MIN(max_size, to_write);
2487 subreq = smb2cli_write_send(state,
2488 state->ev,
2489 state->cli->conn,
2490 state->cli->timeout,
2491 state->cli->smb2.session,
2492 state->cli->smb2.tcon,
2493 to_write,
2494 state->offset,
2495 state->ph->fid_persistent,
2496 state->ph->fid_volatile,
2497 0, /* remaining_bytes */
2498 state->flags, /* flags */
2499 state->buf + state->written);
2501 if (tevent_req_nomem(subreq, req)) {
2502 return tevent_req_post(req, ev);
2504 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2505 return req;
2508 static void cli_smb2_writeall_written(struct tevent_req *subreq)
2510 struct tevent_req *req = tevent_req_callback_data(
2511 subreq, struct tevent_req);
2512 struct cli_smb2_writeall_state *state = tevent_req_data(
2513 req, struct cli_smb2_writeall_state);
2514 NTSTATUS status;
2515 uint32_t written, to_write;
2516 uint32_t max_size;
2517 bool ok;
2519 status = smb2cli_write_recv(subreq, &written);
2520 TALLOC_FREE(subreq);
2521 if (tevent_req_nterror(req, status)) {
2522 return;
2525 state->written += written;
2527 if (state->written > state->size) {
2528 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
2529 return;
2532 to_write = state->size - state->written;
2534 if (to_write == 0) {
2535 tevent_req_done(req);
2536 return;
2539 max_size = smb2cli_conn_max_write_size(state->cli->conn);
2540 to_write = MIN(max_size, to_write);
2541 ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
2542 if (ok) {
2543 to_write = MIN(max_size, to_write);
2546 subreq = smb2cli_write_send(state,
2547 state->ev,
2548 state->cli->conn,
2549 state->cli->timeout,
2550 state->cli->smb2.session,
2551 state->cli->smb2.tcon,
2552 to_write,
2553 state->offset + state->written,
2554 state->ph->fid_persistent,
2555 state->ph->fid_volatile,
2556 0, /* remaining_bytes */
2557 state->flags, /* flags */
2558 state->buf + state->written);
2560 if (tevent_req_nomem(subreq, req)) {
2561 return;
2563 tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
2566 NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
2567 size_t *pwritten)
2569 struct cli_smb2_writeall_state *state = tevent_req_data(
2570 req, struct cli_smb2_writeall_state);
2571 NTSTATUS status;
2573 if (tevent_req_is_nterror(req, &status)) {
2574 return status;
2576 if (pwritten != NULL) {
2577 *pwritten = (size_t)state->written;
2579 return NT_STATUS_OK;