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 15static 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 22static 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 29static 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 39static 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 49static 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 60static 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 */ 78static 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 88static 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 101bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 102 struct cifs_fattr *fattr, 103 struct cifs_open_info_data *data); 104int 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); 107int 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); 110int 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