| /* |
| * This file and its contents are supplied under the terms of the |
| * Common Development and Distribution License ("CDDL"), version 1.0. |
| * You may only use this file in accordance with the terms of version |
| * 1.0 of the CDDL. |
| * |
| * A full copy of the text of the CDDL should have accompanied this |
| * source. A copy of the CDDL is also available via the Internet at |
| * http://www.illumos.org/license/CDDL. |
| */ |
| |
| /* |
| * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. |
| * Copyright 2022 RackTop Systems, Inc. |
| */ |
| |
| /* |
| * Dispatch function for SMB2_QUERY_INFO |
| * |
| * [MS-FSCC 2.4] If a file system does not support ... |
| * an Information Classs, NT_STATUS_INVALID_PARAMETER... |
| */ |
| |
| #include <smbsrv/smb2_kproto.h> |
| #include <smbsrv/smb_fsops.h> |
| #include <smbsrv/ntifs.h> |
| |
| static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_basic(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_standard(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_internal(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_ea_size(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_access(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_name(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_normalized_name(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_position(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_full_ea(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_mode(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_alignment(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_altname(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_stream(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_pipe(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_pipe_lcl(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_pipe_rem(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_compr(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_opens(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_tags(smb_request_t *, smb_queryinfo_t *); |
| static uint32_t smb2_qif_id_info(smb_request_t *, smb_queryinfo_t *); |
| |
| |
| uint32_t |
| smb2_qinfo_file(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| smb_ofile_t *of = sr->fid_ofile; |
| uint_t mask = 0; |
| boolean_t getstd = B_FALSE; |
| boolean_t getname = B_FALSE; |
| uint32_t status; |
| |
| /* |
| * Which attributes do we need from the FS? |
| */ |
| switch (qi->qi_InfoClass) { |
| case FileBasicInformation: |
| mask = SMB_AT_BASIC; |
| break; |
| case FileStandardInformation: |
| mask = SMB_AT_STANDARD; |
| getstd = B_TRUE; |
| break; |
| case FileInternalInformation: |
| mask = SMB_AT_NODEID; |
| break; |
| case FileAllInformation: |
| mask = SMB_AT_ALL; |
| getstd = B_TRUE; |
| if (sr->session->dialect < SMB_VERS_3_11) { |
| /* See smb2_qif_all() */ |
| getname = B_TRUE; |
| } |
| break; |
| |
| case FileNameInformation: |
| case FileNormalizedNameInformation: |
| getname = B_TRUE; |
| break; |
| |
| case FileAlternateNameInformation: |
| mask = SMB_AT_NODEID; |
| getname = B_TRUE; |
| break; |
| |
| case FileStreamInformation: |
| mask = SMB_AT_STANDARD; |
| getstd = B_TRUE; |
| break; |
| |
| case FileCompressionInformation: |
| mask = SMB_AT_SIZE | SMB_AT_ALLOCSZ; |
| break; |
| |
| case FileNetworkOpenInformation: |
| mask = SMB_AT_BASIC | SMB_AT_STANDARD; |
| break; |
| |
| case FileIdInformation: |
| mask = SMB_AT_NODEID; |
| break; |
| |
| default: |
| break; |
| } |
| |
| qi->qi_attr.sa_mask = mask; |
| qi->qi_node = of->f_node; |
| if (mask & SMB_AT_ALL) { |
| status = smb2_ofile_getattr(sr, of, &qi->qi_attr); |
| if (status) |
| return (status); |
| } |
| if (getstd) { |
| status = smb2_ofile_getstd(of, qi); |
| if (status) |
| return (status); |
| } |
| if (getname) { |
| status = smb2_ofile_getname(of, qi); |
| if (status) |
| return (status); |
| } |
| |
| switch (qi->qi_InfoClass) { |
| case FileBasicInformation: |
| status = smb2_qif_basic(sr, qi); |
| break; |
| case FileStandardInformation: |
| status = smb2_qif_standard(sr, qi); |
| break; |
| case FileInternalInformation: |
| status = smb2_qif_internal(sr, qi); |
| break; |
| case FileEaInformation: |
| status = smb2_qif_ea_size(sr, qi); |
| break; |
| case FileAccessInformation: |
| status = smb2_qif_access(sr, qi); |
| break; |
| case FileNameInformation: |
| status = smb2_qif_name(sr, qi); |
| break; |
| case FileNormalizedNameInformation: |
| status = smb2_qif_normalized_name(sr, qi); |
| break; |
| case FilePositionInformation: |
| status = smb2_qif_position(sr, qi); |
| break; |
| case FileFullEaInformation: |
| status = smb2_qif_full_ea(sr, qi); |
| break; |
| case FileModeInformation: |
| status = smb2_qif_mode(sr, qi); |
| break; |
| case FileAlignmentInformation: |
| status = smb2_qif_alignment(sr, qi); |
| break; |
| case FileAllInformation: |
| status = smb2_qif_all(sr, qi); |
| break; |
| case FileAlternateNameInformation: |
| status = smb2_qif_altname(sr, qi); |
| break; |
| case FileStreamInformation: |
| status = smb2_qif_stream(sr, qi); |
| break; |
| case FilePipeInformation: |
| status = smb2_qif_pipe(sr, qi); |
| break; |
| case FilePipeLocalInformation: |
| status = smb2_qif_pipe_lcl(sr, qi); |
| break; |
| case FilePipeRemoteInformation: |
| status = smb2_qif_pipe_rem(sr, qi); |
| break; |
| case FileCompressionInformation: |
| status = smb2_qif_compr(sr, qi); |
| break; |
| case FileNetworkOpenInformation: |
| status = smb2_qif_opens(sr, qi); |
| break; |
| case FileAttributeTagInformation: |
| status = smb2_qif_tags(sr, qi); |
| break; |
| case FileIdInformation: |
| status = smb2_qif_id_info(sr, qi); |
| break; |
| default: |
| status = NT_STATUS_INVALID_INFO_CLASS; |
| break; |
| } |
| |
| return (status); |
| } |
| |
| /* |
| * FileAllInformation |
| * |
| * This returns a concatenation of: |
| * FileBasicInformation |
| * FileStandardInformation |
| * FileInternalInformation |
| * FileEaInformation |
| * FilePositionInformation |
| * FileModeInformation |
| * FileAlignmentInformation |
| * FileNameInformation |
| * |
| * Note: FileNameInformation is all zero on Win2016 and later. |
| */ |
| static uint32_t |
| smb2_qif_all(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| uint32_t status; |
| |
| status = smb2_qif_basic(sr, qi); |
| if (status) |
| return (status); |
| status = smb2_qif_standard(sr, qi); |
| if (status) |
| return (status); |
| status = smb2_qif_internal(sr, qi); |
| if (status) |
| return (status); |
| status = smb2_qif_ea_size(sr, qi); |
| if (status) |
| return (status); |
| status = smb2_qif_position(sr, qi); |
| if (status) |
| return (status); |
| status = smb2_qif_mode(sr, qi); |
| if (status) |
| return (status); |
| status = smb2_qif_alignment(sr, qi); |
| if (status) |
| return (status); |
| |
| /* |
| * MS-SMB2 3.3.5.20.1 says (in a windows behavior note) that |
| * 2012R2 and older fill in the FileNameInformation. |
| * We could let this depend on sr->sr_cfg->skc_version |
| * but doing it based on dialect is a lot easier and |
| * has nearly the same effect. |
| */ |
| if (sr->session->dialect < SMB_VERS_3_11) { |
| /* Win2012r2 and earlier fill it in. (SMB 3.0) */ |
| status = smb2_qif_name(sr, qi); |
| } else { |
| /* Win2016 and later just put zeros (SMB 3.11) */ |
| int rc = smb_mbc_encodef(&sr->raw_data, "10."); |
| status = (rc == 0) ? 0 : NT_STATUS_BUFFER_OVERFLOW; |
| } |
| |
| return (status); |
| } |
| |
| /* |
| * FileBasicInformation |
| * See also: |
| * case SMB_QUERY_FILE_BASIC_INFO: |
| * case SMB_FILE_BASIC_INFORMATION: |
| */ |
| static uint32_t |
| smb2_qif_basic(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| smb_attr_t *sa = &qi->qi_attr; |
| int rc; |
| |
| ASSERT((sa->sa_mask & SMB_AT_BASIC) == SMB_AT_BASIC); |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "TTTTll", |
| &sa->sa_crtime, /* T */ |
| &sa->sa_vattr.va_atime, /* T */ |
| &sa->sa_vattr.va_mtime, /* T */ |
| &sa->sa_vattr.va_ctime, /* T */ |
| sa->sa_dosattr, /* l */ |
| 0); /* reserved */ /* l */ |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileStandardInformation |
| * See also: |
| * SMB_QUERY_FILE_STANDARD_INFO |
| * SMB_FILE_STANDARD_INFORMATION |
| */ |
| static uint32_t |
| smb2_qif_standard(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| smb_attr_t *sa = &qi->qi_attr; |
| int rc; |
| |
| ASSERT((sa->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD); |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "qqlbbw", |
| sa->sa_allocsz, /* q */ |
| sa->sa_vattr.va_size, /* q */ |
| sa->sa_vattr.va_nlink, /* l */ |
| qi->qi_delete_on_close, /* b */ |
| qi->qi_isdir, /* b */ |
| 0); /* reserved */ /* w */ |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileInternalInformation |
| * See also: |
| * SMB_FILE_INTERNAL_INFORMATION |
| */ |
| static uint32_t |
| smb2_qif_internal(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| smb_attr_t *sa = &qi->qi_attr; |
| u_longlong_t nodeid; |
| int rc; |
| |
| ASSERT((sa->sa_mask & SMB_AT_NODEID) == SMB_AT_NODEID); |
| nodeid = sa->sa_vattr.va_nodeid; |
| |
| if (smb2_aapl_use_file_ids == 0 && |
| (sr->session->s_flags & SMB_SSN_AAPL_CCEXT) != 0) |
| nodeid = 0; |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "q", |
| nodeid); /* q */ |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileEaInformation |
| * See also: |
| * SMB_QUERY_FILE_EA_INFO |
| * SMB_FILE_EA_INFORMATION |
| */ |
| static uint32_t |
| smb2_qif_ea_size(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| _NOTE(ARGUNUSED(qi)) |
| int rc; |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "l", 0); |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileFullEaInformation |
| * We could put EAs in a named stream... |
| */ |
| /* ARGSUSED */ |
| static uint32_t |
| smb2_qif_full_ea(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| return (NT_STATUS_NO_EAS_ON_FILE); |
| } |
| |
| /* |
| * FileAccessInformation |
| */ |
| static uint32_t |
| smb2_qif_access(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| _NOTE(ARGUNUSED(qi)) |
| smb_ofile_t *of = sr->fid_ofile; |
| int rc; |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "l", |
| of->f_granted_access); |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileNameInformation |
| * See also: |
| * SMB_QUERY_FILE_NAME_INFO |
| * SMB_FILE_NAME_INFORMATION |
| */ |
| static uint32_t |
| smb2_qif_name(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| char *name; |
| uint32_t nlen; |
| int rc; |
| |
| /* SMB2 leaves off the leading / */ |
| nlen = qi->qi_namelen; |
| name = qi->qi_name; |
| if (qi->qi_name[0] == '\\') { |
| name++; |
| nlen -= 2; |
| } |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "llU", |
| 0, /* FileIndex (l) */ |
| nlen, /* l */ |
| name); /* U */ |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileNormalizedNameInformation |
| */ |
| static uint32_t |
| smb2_qif_normalized_name(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| char *name; |
| uint32_t nlen; |
| int rc; |
| |
| /* SMB2 leaves off the leading / */ |
| nlen = qi->qi_namelen; |
| name = qi->qi_name; |
| if (qi->qi_name[0] == '\\') { |
| name++; |
| nlen -= 2; |
| } |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "lU", |
| nlen, /* l */ |
| name); /* U */ |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FilePositionInformation |
| */ |
| static uint32_t |
| smb2_qif_position(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| _NOTE(ARGUNUSED(qi)) |
| smb_ofile_t *of = sr->fid_ofile; |
| uint64_t pos; |
| int rc; |
| |
| mutex_enter(&of->f_mutex); |
| pos = of->f_seek_pos; |
| mutex_exit(&of->f_mutex); |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "q", pos); |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileModeInformation [MS-FSA 2.4.24] |
| * XXX: These mode flags are supposed to be on the open handle, |
| * XXX: or I think so. Not yet... (just put zero for now) |
| */ |
| static uint32_t |
| smb2_qif_mode(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| _NOTE(ARGUNUSED(qi)) |
| int rc; |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "l", 0); |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileAlignmentInformation |
| */ |
| static uint32_t |
| smb2_qif_alignment(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| _NOTE(ARGUNUSED(qi)) |
| int rc; |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "l", 0); |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileAlternateNameInformation |
| * See also: |
| * SMB_QUERY_FILE_ALT_NAME_INFO |
| * SMB_FILE_ALT_NAME_INFORMATION |
| */ |
| static uint32_t |
| smb2_qif_altname(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| smb_ofile_t *of = sr->fid_ofile; |
| int rc; |
| |
| ASSERT(qi->qi_namelen > 0); |
| ASSERT(qi->qi_attr.sa_mask & SMB_AT_NODEID); |
| |
| if (of->f_ftype != SMB_FTYPE_DISK) |
| return (NT_STATUS_OBJECT_NAME_NOT_FOUND); |
| if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0) |
| return (NT_STATUS_OBJECT_NAME_NOT_FOUND); |
| |
| /* fill in qi->qi_shortname */ |
| smb_query_shortname(of->f_node, qi); |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "%lU", sr, |
| smb_wcequiv_strlen(qi->qi_shortname), |
| qi->qi_shortname); |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileStreamInformation |
| */ |
| static uint32_t |
| smb2_qif_stream(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| smb_ofile_t *of = sr->fid_ofile; |
| smb_attr_t *attr = &qi->qi_attr; |
| uint32_t status; |
| |
| ASSERT((attr->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD); |
| if (of->f_ftype != SMB_FTYPE_DISK) { |
| (void) smb_mbc_encodef( |
| &sr->raw_data, "l", 0); |
| return (0); |
| } |
| |
| status = smb_query_stream_info(sr, &sr->raw_data, qi); |
| return (status); |
| } |
| |
| /* |
| * FilePipeInformation |
| */ |
| static uint32_t |
| smb2_qif_pipe(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| _NOTE(ARGUNUSED(qi)) |
| smb_ofile_t *of = sr->fid_ofile; |
| uint32_t pipe_mode; |
| uint32_t nonblock; |
| int rc; |
| |
| switch (of->f_ftype) { |
| case SMB_FTYPE_BYTE_PIPE: |
| pipe_mode = 0; /* FILE_PIPE_BYTE_STREAM_MODE */ |
| break; |
| case SMB_FTYPE_MESG_PIPE: |
| pipe_mode = 1; /* FILE_PIPE_MESSAGE_MODE */ |
| break; |
| case SMB_FTYPE_DISK: |
| case SMB_FTYPE_PRINTER: |
| default: |
| return (NT_STATUS_INVALID_PARAMETER); |
| } |
| nonblock = 0; /* XXX todo: Get this from the pipe handle. */ |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "ll", |
| pipe_mode, nonblock); |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FilePipeLocalInformation |
| */ |
| /* ARGSUSED */ |
| static uint32_t |
| smb2_qif_pipe_lcl(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */ |
| } |
| |
| /* |
| * FilePipeRemoteInformation |
| */ |
| /* ARGSUSED */ |
| static uint32_t |
| smb2_qif_pipe_rem(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */ |
| } |
| |
| /* |
| * FileCompressionInformation |
| * XXX: For now, just say "not compressed". |
| */ |
| static uint32_t |
| smb2_qif_compr(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| smb_attr_t *sa = &qi->qi_attr; |
| uint16_t CompressionFormat = 0; /* COMPRESSION_FORMAT_NONE */ |
| int rc; |
| |
| ASSERT(sa->sa_mask & SMB_AT_SIZE); |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "qw6.", |
| sa->sa_vattr.va_size, /* q */ |
| CompressionFormat); /* w */ |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileNetworkOpenInformation |
| */ |
| static uint32_t |
| smb2_qif_opens(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| smb_attr_t *sa = &qi->qi_attr; |
| int rc; |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "TTTTqqll", |
| &sa->sa_crtime, /* T */ |
| &sa->sa_vattr.va_atime, /* T */ |
| &sa->sa_vattr.va_mtime, /* T */ |
| &sa->sa_vattr.va_ctime, /* T */ |
| sa->sa_allocsz, /* q */ |
| sa->sa_vattr.va_size, /* q */ |
| sa->sa_dosattr, /* l */ |
| 0); /* reserved */ /* l */ |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileAttributeTagInformation |
| * |
| * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the |
| * second dword should be the reparse tag. Otherwise |
| * the tag value should be set to zero. |
| * We don't support reparse points, so we set the tag |
| * to zero. |
| */ |
| static uint32_t |
| smb2_qif_tags(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| _NOTE(ARGUNUSED(qi)) |
| int rc; |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "ll", 0, 0); |
| if (rc != 0) |
| return (NT_STATUS_BUFFER_OVERFLOW); |
| |
| return (0); |
| } |
| |
| /* |
| * FileIdInformation |
| * |
| * Returns a A FILE_ID_INFORMATION |
| * VolumeSerialNumber (8 bytes) |
| * FileId (16 bytes) |
| * |
| * Take the volume serial from the share root, |
| * and compose the FileId from the nodeid and fsid |
| * of the file (in case we crossed mounts) |
| */ |
| static uint32_t |
| smb2_qif_id_info(smb_request_t *sr, smb_queryinfo_t *qi) |
| { |
| smb_attr_t *sa = &qi->qi_attr; |
| smb_ofile_t *of = sr->fid_ofile; |
| smb_tree_t *tree = sr->tid_tree; |
| vfs_t *f_vfs; // file |
| vfs_t *s_vfs; // share |
| uint64_t nodeid; |
| int rc; |
| |
| ASSERT((sa->sa_mask & SMB_AT_NODEID) != 0); |
| if (of->f_ftype != SMB_FTYPE_DISK) |
| return (NT_STATUS_INVALID_INFO_CLASS); |
| |
| s_vfs = SMB_NODE_VFS(tree->t_snode); |
| f_vfs = SMB_NODE_VFS(of->f_node); |
| nodeid = (uint64_t)sa->sa_vattr.va_nodeid; |
| |
| rc = smb_mbc_encodef( |
| &sr->raw_data, "llqll", |
| s_vfs->vfs_fsid.val[0], /* l */ |
| s_vfs->vfs_fsid.val[1], /* l */ |
| nodeid, /* q */ |
| f_vfs->vfs_fsid.val[0], /* l */ |
| f_vfs->vfs_fsid.val[1]); /* l */ |
| if (rc != 0) |
| return (NT_STATUS_INFO_LENGTH_MISMATCH); |
| |
| return (0); |
| } |