Skip to content

Commit 78e26be

Browse files
Paulo Alcantarasmfrench
authored andcommitted
smb: client: parse uid, gid, mode and dev from WSL reparse points
Parse the extended attributes from WSL reparse points to correctly report uid, gid mode and dev from ther instantiated inodes. Signed-off-by: Paulo Alcantara <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent ea41367 commit 78e26be

File tree

4 files changed

+97
-17
lines changed

4 files changed

+97
-17
lines changed

fs/smb/client/inode.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,8 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
759759
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
760760
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
761761
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
762+
fattr->cf_uid = cifs_sb->ctx->linux_uid;
763+
fattr->cf_gid = cifs_sb->ctx->linux_gid;
762764

763765
fattr->cf_mode = cifs_sb->ctx->file_mode;
764766
if (cifs_open_data_reparse(data) &&
@@ -801,9 +803,6 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
801803
fattr->cf_symlink_target = data->symlink_target;
802804
data->symlink_target = NULL;
803805
}
804-
805-
fattr->cf_uid = cifs_sb->ctx->linux_uid;
806-
fattr->cf_gid = cifs_sb->ctx->linux_gid;
807806
}
808807

809808
static int

fs/smb/client/readdir.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
125125
if (likely(reparse_inode_match(inode, fattr))) {
126126
fattr->cf_mode = inode->i_mode;
127127
fattr->cf_rdev = inode->i_rdev;
128+
fattr->cf_uid = inode->i_uid;
129+
fattr->cf_gid = inode->i_gid;
128130
fattr->cf_eof = CIFS_I(inode)->netfs.remote_i_size;
129131
fattr->cf_symlink_target = NULL;
130132
} else {

fs/smb/client/reparse.c

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,9 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
258258
{
259259
struct cifs_open_info_data data;
260260
struct reparse_data_buffer buf;
261+
struct smb2_create_ea_ctx *cc;
261262
struct inode *new;
263+
unsigned int len;
262264
struct kvec reparse_iov, xattr_iov;
263265
int rc;
264266

@@ -275,6 +277,11 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
275277
.reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, },
276278
};
277279

280+
cc = xattr_iov.iov_base;
281+
len = le32_to_cpu(cc->ctx.DataLength);
282+
memcpy(data.wsl.eas, &cc->ea, len);
283+
data.wsl.eas_len = len;
284+
278285
new = smb2_get_reparse_inode(&data, inode->i_sb,
279286
xid, tcon, full_path,
280287
&reparse_iov, &xattr_iov);
@@ -408,6 +415,62 @@ int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
408415
return parse_reparse_point(buf, plen, cifs_sb, true, data);
409416
}
410417

418+
static void wsl_to_fattr(struct cifs_open_info_data *data,
419+
struct cifs_sb_info *cifs_sb,
420+
u32 tag, struct cifs_fattr *fattr)
421+
{
422+
struct smb2_file_full_ea_info *ea;
423+
u32 next = 0;
424+
425+
switch (tag) {
426+
case IO_REPARSE_TAG_LX_SYMLINK:
427+
fattr->cf_mode |= S_IFLNK;
428+
break;
429+
case IO_REPARSE_TAG_LX_FIFO:
430+
fattr->cf_mode |= S_IFIFO;
431+
break;
432+
case IO_REPARSE_TAG_AF_UNIX:
433+
fattr->cf_mode |= S_IFSOCK;
434+
break;
435+
case IO_REPARSE_TAG_LX_CHR:
436+
fattr->cf_mode |= S_IFCHR;
437+
break;
438+
case IO_REPARSE_TAG_LX_BLK:
439+
fattr->cf_mode |= S_IFBLK;
440+
break;
441+
}
442+
443+
if (!data->wsl.eas_len)
444+
goto out;
445+
446+
ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
447+
do {
448+
const char *name;
449+
void *v;
450+
u8 nlen;
451+
452+
ea = (void *)((u8 *)ea + next);
453+
next = le32_to_cpu(ea->next_entry_offset);
454+
if (!le16_to_cpu(ea->ea_value_length))
455+
continue;
456+
457+
name = ea->ea_data;
458+
nlen = ea->ea_name_length;
459+
v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1);
460+
461+
if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen))
462+
fattr->cf_uid = wsl_make_kuid(cifs_sb, v);
463+
else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen))
464+
fattr->cf_gid = wsl_make_kgid(cifs_sb, v);
465+
else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen))
466+
fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v);
467+
else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen))
468+
fattr->cf_rdev = wsl_mkdev(v);
469+
} while (next);
470+
out:
471+
fattr->cf_dtype = S_DT(fattr->cf_mode);
472+
}
473+
411474
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
412475
struct cifs_fattr *fattr,
413476
struct cifs_open_info_data *data)
@@ -448,24 +511,11 @@ bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
448511

449512
switch (tag) {
450513
case IO_REPARSE_TAG_LX_SYMLINK:
451-
fattr->cf_mode |= S_IFLNK;
452-
fattr->cf_dtype = DT_LNK;
453-
break;
454514
case IO_REPARSE_TAG_LX_FIFO:
455-
fattr->cf_mode |= S_IFIFO;
456-
fattr->cf_dtype = DT_FIFO;
457-
break;
458515
case IO_REPARSE_TAG_AF_UNIX:
459-
fattr->cf_mode |= S_IFSOCK;
460-
fattr->cf_dtype = DT_SOCK;
461-
break;
462516
case IO_REPARSE_TAG_LX_CHR:
463-
fattr->cf_mode |= S_IFCHR;
464-
fattr->cf_dtype = DT_CHR;
465-
break;
466517
case IO_REPARSE_TAG_LX_BLK:
467-
fattr->cf_mode |= S_IFBLK;
468-
fattr->cf_dtype = DT_BLK;
518+
wsl_to_fattr(data, cifs_sb, tag, fattr);
469519
break;
470520
case 0: /* SMB1 symlink */
471521
case IO_REPARSE_TAG_SYMLINK:

fs/smb/client/reparse.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include <linux/fs.h>
1010
#include <linux/stat.h>
11+
#include <linux/uidgid.h>
12+
#include "fs_context.h"
1113
#include "cifsglob.h"
1214

1315
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)
1719
return MKDEV(v >> 32, v & 0xffffffff);
1820
}
1921

22+
static inline dev_t wsl_mkdev(void *ptr)
23+
{
24+
u64 v = le64_to_cpu(*(__le64 *)ptr);
25+
26+
return MKDEV(v & 0xffffffff, v >> 32);
27+
}
28+
29+
static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb,
30+
void *ptr)
31+
{
32+
u32 uid = le32_to_cpu(*(__le32 *)ptr);
33+
34+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
35+
return cifs_sb->ctx->linux_uid;
36+
return make_kuid(current_user_ns(), uid);
37+
}
38+
39+
static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb,
40+
void *ptr)
41+
{
42+
u32 gid = le32_to_cpu(*(__le32 *)ptr);
43+
44+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
45+
return cifs_sb->ctx->linux_gid;
46+
return make_kgid(current_user_ns(), gid);
47+
}
48+
2049
static inline u64 reparse_mode_nfs_type(mode_t mode)
2150
{
2251
switch (mode & S_IFMT) {

0 commit comments

Comments
 (0)