xref: /openbmc/linux/fs/smb/client/reparse.h (revision ecc23d0a422a3118fcf6e4f0a46e17a6c2047b02)
1db0f1c07SPaulo Alcantara /* SPDX-License-Identifier: GPL-2.0-only */
2db0f1c07SPaulo Alcantara /*
3db0f1c07SPaulo Alcantara  * Copyright (c) 2024 Paulo Alcantara <pc@manguebit.com>
4db0f1c07SPaulo Alcantara  */
5db0f1c07SPaulo Alcantara 
6db0f1c07SPaulo Alcantara #ifndef _CIFS_REPARSE_H
7db0f1c07SPaulo Alcantara #define _CIFS_REPARSE_H
8db0f1c07SPaulo Alcantara 
9db0f1c07SPaulo Alcantara #include <linux/fs.h>
10db0f1c07SPaulo Alcantara #include <linux/stat.h>
1197db4160SPaulo Alcantara #include <linux/uidgid.h>
1297db4160SPaulo Alcantara #include "fs_context.h"
13db0f1c07SPaulo Alcantara #include "cifsglob.h"
14db0f1c07SPaulo Alcantara 
15921d9090SPaulo Alcantara #define REPARSE_SYM_PATH_MAX 4060
16921d9090SPaulo Alcantara 
170397a48cSPaulo Alcantara /*
180397a48cSPaulo Alcantara  * Used only by cifs.ko to ignore reparse points from files when client or
190397a48cSPaulo Alcantara  * server doesn't support FSCTL_GET_REPARSE_POINT.
200397a48cSPaulo Alcantara  */
210397a48cSPaulo Alcantara #define IO_REPARSE_TAG_INTERNAL ((__u32)~0U)
220397a48cSPaulo Alcantara 
reparse_mkdev(void * ptr)23bbc258dcSPaulo Alcantara static inline dev_t reparse_mkdev(void *ptr)
2497db4160SPaulo Alcantara {
2597db4160SPaulo Alcantara 	u64 v = le64_to_cpu(*(__le64 *)ptr);
2697db4160SPaulo Alcantara 
2797db4160SPaulo Alcantara 	return MKDEV(v & 0xffffffff, v >> 32);
2897db4160SPaulo Alcantara }
2997db4160SPaulo Alcantara 
wsl_make_kuid(struct cifs_sb_info * cifs_sb,void * ptr)3097db4160SPaulo Alcantara static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb,
3197db4160SPaulo Alcantara 				   void *ptr)
3297db4160SPaulo Alcantara {
3397db4160SPaulo Alcantara 	u32 uid = le32_to_cpu(*(__le32 *)ptr);
3497db4160SPaulo Alcantara 
3597db4160SPaulo Alcantara 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
3697db4160SPaulo Alcantara 		return cifs_sb->ctx->linux_uid;
3797db4160SPaulo Alcantara 	return make_kuid(current_user_ns(), uid);
3897db4160SPaulo Alcantara }
3997db4160SPaulo Alcantara 
wsl_make_kgid(struct cifs_sb_info * cifs_sb,void * ptr)4097db4160SPaulo Alcantara static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb,
4197db4160SPaulo Alcantara 				   void *ptr)
4297db4160SPaulo Alcantara {
4397db4160SPaulo Alcantara 	u32 gid = le32_to_cpu(*(__le32 *)ptr);
4497db4160SPaulo Alcantara 
4597db4160SPaulo Alcantara 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
4697db4160SPaulo Alcantara 		return cifs_sb->ctx->linux_gid;
4797db4160SPaulo Alcantara 	return make_kgid(current_user_ns(), gid);
4897db4160SPaulo Alcantara }
4997db4160SPaulo Alcantara 
reparse_mode_nfs_type(mode_t mode)50db0f1c07SPaulo Alcantara static inline u64 reparse_mode_nfs_type(mode_t mode)
51db0f1c07SPaulo Alcantara {
52db0f1c07SPaulo Alcantara 	switch (mode & S_IFMT) {
53db0f1c07SPaulo Alcantara 	case S_IFBLK: return NFS_SPECFILE_BLK;
54db0f1c07SPaulo Alcantara 	case S_IFCHR: return NFS_SPECFILE_CHR;
55db0f1c07SPaulo Alcantara 	case S_IFIFO: return NFS_SPECFILE_FIFO;
56db0f1c07SPaulo Alcantara 	case S_IFSOCK: return NFS_SPECFILE_SOCK;
57db0f1c07SPaulo Alcantara 	}
58db0f1c07SPaulo Alcantara 	return 0;
59db0f1c07SPaulo Alcantara }
60db0f1c07SPaulo Alcantara 
reparse_mode_wsl_tag(mode_t mode)61df0a8a19SPaulo Alcantara static inline u32 reparse_mode_wsl_tag(mode_t mode)
62df0a8a19SPaulo Alcantara {
63df0a8a19SPaulo Alcantara 	switch (mode & S_IFMT) {
64df0a8a19SPaulo Alcantara 	case S_IFBLK: return IO_REPARSE_TAG_LX_BLK;
65df0a8a19SPaulo Alcantara 	case S_IFCHR: return IO_REPARSE_TAG_LX_CHR;
66df0a8a19SPaulo Alcantara 	case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO;
67df0a8a19SPaulo Alcantara 	case S_IFSOCK: return IO_REPARSE_TAG_AF_UNIX;
68df0a8a19SPaulo Alcantara 	}
69df0a8a19SPaulo Alcantara 	return 0;
70df0a8a19SPaulo Alcantara }
71df0a8a19SPaulo Alcantara 
72db0f1c07SPaulo Alcantara /*
73db0f1c07SPaulo Alcantara  * Match a reparse point inode if reparse tag and ctime haven't changed.
74db0f1c07SPaulo Alcantara  *
75db0f1c07SPaulo Alcantara  * Windows Server updates ctime of reparse points when their data have changed.
76db0f1c07SPaulo Alcantara  * The server doesn't allow changing reparse tags from existing reparse points,
77db0f1c07SPaulo Alcantara  * though it's worth checking.
78db0f1c07SPaulo Alcantara  */
reparse_inode_match(struct inode * inode,struct cifs_fattr * fattr)79db0f1c07SPaulo Alcantara static inline bool reparse_inode_match(struct inode *inode,
80db0f1c07SPaulo Alcantara 				       struct cifs_fattr *fattr)
81db0f1c07SPaulo Alcantara {
820397a48cSPaulo Alcantara 	struct cifsInodeInfo *cinode = CIFS_I(inode);
83db0f1c07SPaulo Alcantara 	struct timespec64 ctime = inode_get_ctime(inode);
84db0f1c07SPaulo Alcantara 
850397a48cSPaulo Alcantara 	/*
860397a48cSPaulo Alcantara 	 * Do not match reparse tags when client or server doesn't support
870397a48cSPaulo Alcantara 	 * FSCTL_GET_REPARSE_POINT.  @fattr->cf_cifstag should contain correct
880397a48cSPaulo Alcantara 	 * reparse tag from query dir response but the client won't be able to
890397a48cSPaulo Alcantara 	 * read the reparse point data anyway.  This spares us a revalidation.
900397a48cSPaulo Alcantara 	 */
910397a48cSPaulo Alcantara 	if (cinode->reparse_tag != IO_REPARSE_TAG_INTERNAL &&
920397a48cSPaulo Alcantara 	    cinode->reparse_tag != fattr->cf_cifstag)
930397a48cSPaulo Alcantara 		return false;
940397a48cSPaulo Alcantara 	return (cinode->cifsAttrs & ATTR_REPARSE) &&
95db0f1c07SPaulo Alcantara 		timespec64_equal(&ctime, &fattr->cf_ctime);
96db0f1c07SPaulo Alcantara }
97db0f1c07SPaulo Alcantara 
cifs_open_data_reparse(struct cifs_open_info_data * data)98db0f1c07SPaulo Alcantara static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
99db0f1c07SPaulo Alcantara {
100db0f1c07SPaulo Alcantara 	struct smb2_file_all_info *fi = &data->fi;
101db0f1c07SPaulo Alcantara 	u32 attrs = le32_to_cpu(fi->Attributes);
102db0f1c07SPaulo Alcantara 	bool ret;
103db0f1c07SPaulo Alcantara 
104db0f1c07SPaulo Alcantara 	ret = data->reparse_point || (attrs & ATTR_REPARSE);
105db0f1c07SPaulo Alcantara 	if (ret)
106db0f1c07SPaulo Alcantara 		attrs |= ATTR_REPARSE;
107db0f1c07SPaulo Alcantara 	fi->Attributes = cpu_to_le32(attrs);
108db0f1c07SPaulo Alcantara 	return ret;
109db0f1c07SPaulo Alcantara }
110db0f1c07SPaulo Alcantara 
111db0f1c07SPaulo Alcantara bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
112db0f1c07SPaulo Alcantara 				 struct cifs_fattr *fattr,
113db0f1c07SPaulo Alcantara 				 struct cifs_open_info_data *data);
114db0f1c07SPaulo Alcantara int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
115db0f1c07SPaulo Alcantara 				struct dentry *dentry, struct cifs_tcon *tcon,
116db0f1c07SPaulo Alcantara 				const char *full_path, const char *symname);
117df0a8a19SPaulo Alcantara int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
118db0f1c07SPaulo Alcantara 		       struct dentry *dentry, struct cifs_tcon *tcon,
119db0f1c07SPaulo Alcantara 		       const char *full_path, umode_t mode, dev_t dev);
120*430afd3eSPali Rohár int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
121*430afd3eSPali Rohár 			     const char *full_path,
122*430afd3eSPali Rohár 			     struct kvec *rsp_iov,
123db0f1c07SPaulo Alcantara 			     struct cifs_open_info_data *data);
124db0f1c07SPaulo Alcantara 
125db0f1c07SPaulo Alcantara #endif /* _CIFS_REPARSE_H */
126