From: Jule Anger Date: Tue, 3 Sep 2024 12:41:40 +0000 (+0200) Subject: libsmb: add cli_get_posix_fs_info() for smb2 X-Git-Tag: tdb-1.4.13~940 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b8dbf743c1375f47219b73c37e67ce48bd1476cd;p=thirdparty%2Fsamba.git libsmb: add cli_get_posix_fs_info() for smb2 Signed-off-by: Jule Anger Reviewed-by: Volker Lendecke --- diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c index b8c2e9a8acb..91933c6efe9 100644 --- a/source3/libsmb/cli_smb2_fnum.c +++ b/source3/libsmb/cli_smb2_fnum.c @@ -45,6 +45,7 @@ #include "librpc/gen_ndr/ndr_smb3posix.h" #include "lib/util/string_wrappers.h" #include "lib/util/idtree.h" +#include "libcli/smb/smb2_posix.h" struct smb2_hnd { uint64_t fid_persistent; @@ -4990,3 +4991,191 @@ NTSTATUS cli_smb2_fsctl_recv( tevent_req_received(req); return NT_STATUS_OK; } + +struct cli_smb2_get_posix_fs_info_state { + struct tevent_context *ev; + struct cli_state *cli; + uint16_t fnum; + uint32_t optimal_transfer_size; + uint32_t block_size; + uint64_t total_blocks; + uint64_t blocks_available; + uint64_t user_blocks_available; + uint64_t total_file_nodes; + uint64_t free_file_nodes; + uint64_t fs_identifier; +}; + +static void cli_smb2_get_posix_fs_info_opened(struct tevent_req *subreq); +static void cli_smb2_get_posix_fs_info_queried(struct tevent_req *subreq); +static void cli_smb2_get_posix_fs_info_done(struct tevent_req *subreq); + +struct tevent_req *cli_smb2_get_posix_fs_info_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli) +{ + struct smb2_create_blobs *cblob = NULL; + struct tevent_req *req = NULL, *subreq = NULL; + struct cli_smb2_get_posix_fs_info_state *state = NULL; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, struct cli_smb2_get_posix_fs_info_state); + if (req == NULL) { + return NULL; + } + *state = (struct cli_smb2_get_posix_fs_info_state) { + .ev = ev, + .cli = cli, + }; + status = make_smb2_posix_create_ctx(state, &cblob, 0); + if (!NT_STATUS_IS_OK(status)) { + return NULL; + } + + /* First open the top level directory. */ + subreq = cli_smb2_create_fnum_send(state, + state->ev, + state->cli, + "", + (struct cli_smb2_create_flags){0}, + SMB2_IMPERSONATION_IMPERSONATION, + FILE_READ_ATTRIBUTES, + FILE_ATTRIBUTE_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_WRITE | + FILE_SHARE_DELETE, + FILE_OPEN, + FILE_DIRECTORY_FILE, + cblob); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + + tevent_req_set_callback(subreq, cli_smb2_get_posix_fs_info_opened, req); + return req; +} + +static void cli_smb2_get_posix_fs_info_opened(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb2_get_posix_fs_info_state *state = tevent_req_data( + req, struct cli_smb2_get_posix_fs_info_state); + struct smb2_create_blobs *cblob = {0}; + NTSTATUS status; + + status = cli_smb2_create_fnum_recv(subreq, + &state->fnum, + NULL, + state, + cblob, + NULL); + TALLOC_FREE(subreq); + + if (tevent_req_nterror(req, status)) { + return; + } + + subreq = cli_smb2_query_info_fnum_send( + state, + state->ev, + state->cli, + state->fnum, + SMB2_0_INFO_FILESYSTEM, /* in_info_type */ + SMB2_FS_POSIX_INFORMATION, /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0); /* in_flags */ + if (tevent_req_nomem(subreq, req)) { + return; + } + + tevent_req_set_callback(subreq, cli_smb2_get_posix_fs_info_queried, req); +} + +static void cli_smb2_get_posix_fs_info_queried(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb2_get_posix_fs_info_state *state = tevent_req_data( + req, struct cli_smb2_get_posix_fs_info_state); + DATA_BLOB outbuf = data_blob_null; + NTSTATUS status; + + status = cli_smb2_query_info_fnum_recv(subreq, state, &outbuf); + TALLOC_FREE(subreq); + + if (tevent_req_nterror(req, status)) { + return; + } + + if (outbuf.length != 56) { + goto close; + } + + state->optimal_transfer_size = PULL_LE_U32(outbuf.data, 0); + state->block_size = PULL_LE_U32(outbuf.data, 4); + state->total_blocks = PULL_LE_U64(outbuf.data, 8); + state->blocks_available = PULL_LE_U64(outbuf.data, 16); + state->user_blocks_available = PULL_LE_U64(outbuf.data, 24); + state->total_file_nodes = PULL_LE_U64(outbuf.data, 32); + state->free_file_nodes = PULL_LE_U64(outbuf.data, 40); + state->fs_identifier = PULL_LE_U64(outbuf.data, 48); + +close: + subreq = cli_smb2_close_fnum_send(state, + state->ev, + state->cli, + state->fnum, + 0); + if (tevent_req_nomem(subreq, req)) { + return; + } + + tevent_req_set_callback(subreq, cli_smb2_get_posix_fs_info_done, req); +} + +static void cli_smb2_get_posix_fs_info_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = cli_smb2_close_fnum_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + tevent_req_done(req); +} + +NTSTATUS cli_smb2_get_posix_fs_info_recv(struct tevent_req *req, + uint32_t *optimal_transfer_size, + uint32_t *block_size, + uint64_t *total_blocks, + uint64_t *blocks_available, + uint64_t *user_blocks_available, + uint64_t *total_file_nodes, + uint64_t *free_file_nodes, + uint64_t *fs_identifier) +{ + struct cli_smb2_get_posix_fs_info_state *state = tevent_req_data( + req, struct cli_smb2_get_posix_fs_info_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + *optimal_transfer_size = state->optimal_transfer_size; + *block_size = state->block_size; + *total_blocks = state->total_blocks; + *blocks_available = state->blocks_available; + *user_blocks_available = state->user_blocks_available; + *total_file_nodes = state->total_file_nodes; + *free_file_nodes = state->free_file_nodes; + *fs_identifier = state->fs_identifier; + tevent_req_received(req); + return NT_STATUS_OK; +} diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h index 2b19e6ebb4e..4399cf31981 100644 --- a/source3/libsmb/cli_smb2_fnum.h +++ b/source3/libsmb/cli_smb2_fnum.h @@ -323,4 +323,18 @@ struct tevent_req *cli_smb2_fsctl_send( NTSTATUS cli_smb2_fsctl_recv( struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out); +struct tevent_req *cli_smb2_get_posix_fs_info_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli); +NTSTATUS cli_smb2_get_posix_fs_info_recv(struct tevent_req *req, + uint32_t *optimal_transfer_size, + uint32_t *block_size, + uint64_t *total_blocks, + uint64_t *blocks_available, + uint64_t *user_blocks_available, + uint64_t *total_file_nodes, + uint64_t *free_file_nodes, + uint64_t *fs_identifier); + + #endif /* __SMB2CLI_FNUM_H__ */ diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c index 54804e566f3..4b82a0bd1e9 100644 --- a/source3/libsmb/clifsinfo.c +++ b/source3/libsmb/clifsinfo.c @@ -499,6 +499,7 @@ struct cli_get_posix_fs_info_state { }; static void cli_get_posix_fs_info_done(struct tevent_req *subreq); +static void cli_get_posix_fs_info_done2(struct tevent_req *subreq); struct tevent_req *cli_get_posix_fs_info_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -515,6 +516,15 @@ struct tevent_req *cli_get_posix_fs_info_send(TALLOC_CTX *mem_ctx, SSVAL(state->setup, 0, TRANSACT2_QFSINFO); SSVAL(state->param, 0, SMB_QUERY_POSIX_FS_INFO); + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + subreq = cli_smb2_get_posix_fs_info_send(mem_ctx, ev, cli); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_get_posix_fs_info_done2, req); + return req; + } + subreq = cli_trans_send(talloc_tos(), /* mem ctx. */ ev, /* event ctx. */ cli, /* cli_state. */ @@ -570,6 +580,30 @@ static void cli_get_posix_fs_info_done(struct tevent_req *subreq) tevent_req_done(req); } +static void cli_get_posix_fs_info_done2(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_get_posix_fs_info_state *state = tevent_req_data( + req, struct cli_get_posix_fs_info_state); + NTSTATUS status; + status = cli_smb2_get_posix_fs_info_recv(subreq, + &state->optimal_transfer_size, + &state->block_size, + &state->total_blocks, + &state->blocks_available, + &state->user_blocks_available, + &state->total_file_nodes, + &state->free_file_nodes, + &state->fs_identifier); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + tevent_req_done(req); +} + NTSTATUS cli_get_posix_fs_info_recv(struct tevent_req *req, uint32_t *optimal_transfer_size, uint32_t *block_size,