diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index 540dca85fae0..8177ec59afee 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -759,6 +759,8 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, fattr->cf_bytes = le64_to_cpu(info->AllocationSize); fattr->cf_createtime = le64_to_cpu(info->CreationTime); fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); + fattr->cf_uid = cifs_sb->ctx->linux_uid; + fattr->cf_gid = cifs_sb->ctx->linux_gid; fattr->cf_mode = cifs_sb->ctx->file_mode; if (cifs_open_data_reparse(data) && @@ -801,9 +803,6 @@ out_reparse: fattr->cf_symlink_target = data->symlink_target; data->symlink_target = NULL; } - - fattr->cf_uid = cifs_sb->ctx->linux_uid; - fattr->cf_gid = cifs_sb->ctx->linux_gid; } static int diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c index 88c88d50297c..ebe1cb30e18e 100644 --- a/fs/smb/client/readdir.c +++ b/fs/smb/client/readdir.c @@ -125,6 +125,8 @@ retry: if (likely(reparse_inode_match(inode, fattr))) { fattr->cf_mode = inode->i_mode; fattr->cf_rdev = inode->i_rdev; + fattr->cf_uid = inode->i_uid; + fattr->cf_gid = inode->i_gid; fattr->cf_eof = CIFS_I(inode)->netfs.remote_i_size; fattr->cf_symlink_target = NULL; } else { diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c index e8be756e6768..29a47f20643b 100644 --- a/fs/smb/client/reparse.c +++ b/fs/smb/client/reparse.c @@ -258,7 +258,9 @@ static int mknod_wsl(unsigned int xid, struct inode *inode, { struct cifs_open_info_data data; struct reparse_data_buffer buf; + struct smb2_create_ea_ctx *cc; struct inode *new; + unsigned int len; struct kvec reparse_iov, xattr_iov; int rc; @@ -275,6 +277,11 @@ static int mknod_wsl(unsigned int xid, struct inode *inode, .reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, }, }; + cc = xattr_iov.iov_base; + len = le32_to_cpu(cc->ctx.DataLength); + memcpy(data.wsl.eas, &cc->ea, len); + data.wsl.eas_len = len; + new = smb2_get_reparse_inode(&data, inode->i_sb, xid, tcon, full_path, &reparse_iov, &xattr_iov); @@ -408,6 +415,62 @@ int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb, return parse_reparse_point(buf, plen, cifs_sb, true, data); } +static void wsl_to_fattr(struct cifs_open_info_data *data, + struct cifs_sb_info *cifs_sb, + u32 tag, struct cifs_fattr *fattr) +{ + struct smb2_file_full_ea_info *ea; + u32 next = 0; + + switch (tag) { + case IO_REPARSE_TAG_LX_SYMLINK: + fattr->cf_mode |= S_IFLNK; + break; + case IO_REPARSE_TAG_LX_FIFO: + fattr->cf_mode |= S_IFIFO; + break; + case IO_REPARSE_TAG_AF_UNIX: + fattr->cf_mode |= S_IFSOCK; + break; + case IO_REPARSE_TAG_LX_CHR: + fattr->cf_mode |= S_IFCHR; + break; + case IO_REPARSE_TAG_LX_BLK: + fattr->cf_mode |= S_IFBLK; + break; + } + + if (!data->wsl.eas_len) + goto out; + + ea = (struct smb2_file_full_ea_info *)data->wsl.eas; + do { + const char *name; + void *v; + u8 nlen; + + ea = (void *)((u8 *)ea + next); + next = le32_to_cpu(ea->next_entry_offset); + if (!le16_to_cpu(ea->ea_value_length)) + continue; + + name = ea->ea_data; + nlen = ea->ea_name_length; + v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1); + + if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen)) + fattr->cf_uid = wsl_make_kuid(cifs_sb, v); + else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen)) + fattr->cf_gid = wsl_make_kgid(cifs_sb, v); + else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen)) + fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v); + else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen)) + fattr->cf_rdev = wsl_mkdev(v); + } while (next); +out: + fattr->cf_dtype = S_DT(fattr->cf_mode); +} + bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, struct cifs_open_info_data *data) @@ -448,24 +511,11 @@ bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, switch (tag) { case IO_REPARSE_TAG_LX_SYMLINK: - fattr->cf_mode |= S_IFLNK; - fattr->cf_dtype = DT_LNK; - break; case IO_REPARSE_TAG_LX_FIFO: - fattr->cf_mode |= S_IFIFO; - fattr->cf_dtype = DT_FIFO; - break; case IO_REPARSE_TAG_AF_UNIX: - fattr->cf_mode |= S_IFSOCK; - fattr->cf_dtype = DT_SOCK; - break; case IO_REPARSE_TAG_LX_CHR: - fattr->cf_mode |= S_IFCHR; - fattr->cf_dtype = DT_CHR; - break; case IO_REPARSE_TAG_LX_BLK: - fattr->cf_mode |= S_IFBLK; - fattr->cf_dtype = DT_BLK; + wsl_to_fattr(data, cifs_sb, tag, fattr); break; case 0: /* SMB1 symlink */ case IO_REPARSE_TAG_SYMLINK: diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h index 9816bac98552..6b55d1df9e2f 100644 --- a/fs/smb/client/reparse.h +++ b/fs/smb/client/reparse.h @@ -8,6 +8,8 @@ #include #include +#include +#include "fs_context.h" #include "cifsglob.h" static inline dev_t reparse_nfs_mkdev(struct reparse_posix_data *buf) @@ -17,6 +19,33 @@ static inline dev_t reparse_nfs_mkdev(struct reparse_posix_data *buf) return MKDEV(v >> 32, v & 0xffffffff); } +static inline dev_t wsl_mkdev(void *ptr) +{ + u64 v = le64_to_cpu(*(__le64 *)ptr); + + return MKDEV(v & 0xffffffff, v >> 32); +} + +static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb, + void *ptr) +{ + u32 uid = le32_to_cpu(*(__le32 *)ptr); + + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) + return cifs_sb->ctx->linux_uid; + return make_kuid(current_user_ns(), uid); +} + +static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb, + void *ptr) +{ + u32 gid = le32_to_cpu(*(__le32 *)ptr); + + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) + return cifs_sb->ctx->linux_gid; + return make_kgid(current_user_ns(), gid); +} + static inline u64 reparse_mode_nfs_type(mode_t mode) { switch (mode & S_IFMT) {