1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright (c) 2024 Paulo Alcantara <pc@manguebit.com> 4 */ 5 6 #ifndef _CIFS_REPARSE_H 7 #define _CIFS_REPARSE_H 8 9 #include <linux/fs.h> 10 #include <linux/stat.h> 11 #include <linux/uidgid.h> 12 #include "fs_context.h" 13 #include "cifsglob.h" 14 15 static inline dev_t reparse_nfs_mkdev(struct reparse_posix_data *buf) 16 { 17 u64 v = le64_to_cpu(*(__le64 *)buf->DataBuffer); 18 19 return MKDEV(v >> 32, v & 0xffffffff); 20 } 21 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 49 static inline u64 reparse_mode_nfs_type(mode_t mode) 50 { 51 switch (mode & S_IFMT) { 52 case S_IFBLK: return NFS_SPECFILE_BLK; 53 case S_IFCHR: return NFS_SPECFILE_CHR; 54 case S_IFIFO: return NFS_SPECFILE_FIFO; 55 case S_IFSOCK: return NFS_SPECFILE_SOCK; 56 } 57 return 0; 58 } 59 60 static inline u32 reparse_mode_wsl_tag(mode_t mode) 61 { 62 switch (mode & S_IFMT) { 63 case S_IFBLK: return IO_REPARSE_TAG_LX_BLK; 64 case S_IFCHR: return IO_REPARSE_TAG_LX_CHR; 65 case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO; 66 case S_IFSOCK: return IO_REPARSE_TAG_AF_UNIX; 67 } 68 return 0; 69 } 70 71 /* 72 * Match a reparse point inode if reparse tag and ctime haven't changed. 73 * 74 * Windows Server updates ctime of reparse points when their data have changed. 75 * The server doesn't allow changing reparse tags from existing reparse points, 76 * though it's worth checking. 77 */ 78 static inline bool reparse_inode_match(struct inode *inode, 79 struct cifs_fattr *fattr) 80 { 81 struct timespec64 ctime = inode_get_ctime(inode); 82 83 return (CIFS_I(inode)->cifsAttrs & ATTR_REPARSE) && 84 CIFS_I(inode)->reparse_tag == fattr->cf_cifstag && 85 timespec64_equal(&ctime, &fattr->cf_ctime); 86 } 87 88 static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data) 89 { 90 struct smb2_file_all_info *fi = &data->fi; 91 u32 attrs = le32_to_cpu(fi->Attributes); 92 bool ret; 93 94 ret = data->reparse_point || (attrs & ATTR_REPARSE); 95 if (ret) 96 attrs |= ATTR_REPARSE; 97 fi->Attributes = cpu_to_le32(attrs); 98 return ret; 99 } 100 101 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 102 struct cifs_fattr *fattr, 103 struct cifs_open_info_data *data); 104 int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode, 105 struct dentry *dentry, struct cifs_tcon *tcon, 106 const char *full_path, const char *symname); 107 int smb2_mknod_reparse(unsigned int xid, struct inode *inode, 108 struct dentry *dentry, struct cifs_tcon *tcon, 109 const char *full_path, umode_t mode, dev_t dev); 110 int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb, struct kvec *rsp_iov, 111 struct cifs_open_info_data *data); 112 113 #endif /* _CIFS_REPARSE_H */ 114