xref: /openbmc/linux/fs/smb/client/reparse.h (revision 97db4160)
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 
reparse_nfs_mkdev(struct reparse_posix_data * buf)15db0f1c07SPaulo Alcantara static inline dev_t reparse_nfs_mkdev(struct reparse_posix_data *buf)
16db0f1c07SPaulo Alcantara {
17db0f1c07SPaulo Alcantara 	u64 v = le64_to_cpu(*(__le64 *)buf->DataBuffer);
18db0f1c07SPaulo Alcantara 
19db0f1c07SPaulo Alcantara 	return MKDEV(v >> 32, v & 0xffffffff);
20db0f1c07SPaulo Alcantara }
21db0f1c07SPaulo Alcantara 
wsl_mkdev(void * ptr)2297db4160SPaulo Alcantara static inline dev_t wsl_mkdev(void *ptr)
2397db4160SPaulo Alcantara {
2497db4160SPaulo Alcantara 	u64 v = le64_to_cpu(*(__le64 *)ptr);
2597db4160SPaulo Alcantara 
2697db4160SPaulo Alcantara 	return MKDEV(v & 0xffffffff, v >> 32);
2797db4160SPaulo Alcantara }
2897db4160SPaulo Alcantara 
wsl_make_kuid(struct cifs_sb_info * cifs_sb,void * ptr)2997db4160SPaulo Alcantara static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb,
3097db4160SPaulo Alcantara 				   void *ptr)
3197db4160SPaulo Alcantara {
3297db4160SPaulo Alcantara 	u32 uid = le32_to_cpu(*(__le32 *)ptr);
3397db4160SPaulo Alcantara 
3497db4160SPaulo Alcantara 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
3597db4160SPaulo Alcantara 		return cifs_sb->ctx->linux_uid;
3697db4160SPaulo Alcantara 	return make_kuid(current_user_ns(), uid);
3797db4160SPaulo Alcantara }
3897db4160SPaulo Alcantara 
wsl_make_kgid(struct cifs_sb_info * cifs_sb,void * ptr)3997db4160SPaulo Alcantara static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb,
4097db4160SPaulo Alcantara 				   void *ptr)
4197db4160SPaulo Alcantara {
4297db4160SPaulo Alcantara 	u32 gid = le32_to_cpu(*(__le32 *)ptr);
4397db4160SPaulo Alcantara 
4497db4160SPaulo Alcantara 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
4597db4160SPaulo Alcantara 		return cifs_sb->ctx->linux_gid;
4697db4160SPaulo Alcantara 	return make_kgid(current_user_ns(), gid);
4797db4160SPaulo Alcantara }
4897db4160SPaulo Alcantara 
reparse_mode_nfs_type(mode_t mode)49db0f1c07SPaulo Alcantara static inline u64 reparse_mode_nfs_type(mode_t mode)
50db0f1c07SPaulo Alcantara {
51db0f1c07SPaulo Alcantara 	switch (mode & S_IFMT) {
52db0f1c07SPaulo Alcantara 	case S_IFBLK: return NFS_SPECFILE_BLK;
53db0f1c07SPaulo Alcantara 	case S_IFCHR: return NFS_SPECFILE_CHR;
54db0f1c07SPaulo Alcantara 	case S_IFIFO: return NFS_SPECFILE_FIFO;
55db0f1c07SPaulo Alcantara 	case S_IFSOCK: return NFS_SPECFILE_SOCK;
56db0f1c07SPaulo Alcantara 	}
57db0f1c07SPaulo Alcantara 	return 0;
58db0f1c07SPaulo Alcantara }
59db0f1c07SPaulo Alcantara 
reparse_mode_wsl_tag(mode_t mode)60df0a8a19SPaulo Alcantara static inline u32 reparse_mode_wsl_tag(mode_t mode)
61df0a8a19SPaulo Alcantara {
62df0a8a19SPaulo Alcantara 	switch (mode & S_IFMT) {
63df0a8a19SPaulo Alcantara 	case S_IFBLK: return IO_REPARSE_TAG_LX_BLK;
64df0a8a19SPaulo Alcantara 	case S_IFCHR: return IO_REPARSE_TAG_LX_CHR;
65df0a8a19SPaulo Alcantara 	case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO;
66df0a8a19SPaulo Alcantara 	case S_IFSOCK: return IO_REPARSE_TAG_AF_UNIX;
67df0a8a19SPaulo Alcantara 	}
68df0a8a19SPaulo Alcantara 	return 0;
69df0a8a19SPaulo Alcantara }
70df0a8a19SPaulo Alcantara 
71db0f1c07SPaulo Alcantara /*
72db0f1c07SPaulo Alcantara  * Match a reparse point inode if reparse tag and ctime haven't changed.
73db0f1c07SPaulo Alcantara  *
74db0f1c07SPaulo Alcantara  * Windows Server updates ctime of reparse points when their data have changed.
75db0f1c07SPaulo Alcantara  * The server doesn't allow changing reparse tags from existing reparse points,
76db0f1c07SPaulo Alcantara  * though it's worth checking.
77db0f1c07SPaulo Alcantara  */
reparse_inode_match(struct inode * inode,struct cifs_fattr * fattr)78db0f1c07SPaulo Alcantara static inline bool reparse_inode_match(struct inode *inode,
79db0f1c07SPaulo Alcantara 				       struct cifs_fattr *fattr)
80db0f1c07SPaulo Alcantara {
81db0f1c07SPaulo Alcantara 	struct timespec64 ctime = inode_get_ctime(inode);
82db0f1c07SPaulo Alcantara 
83db0f1c07SPaulo Alcantara 	return (CIFS_I(inode)->cifsAttrs & ATTR_REPARSE) &&
84db0f1c07SPaulo Alcantara 		CIFS_I(inode)->reparse_tag == fattr->cf_cifstag &&
85db0f1c07SPaulo Alcantara 		timespec64_equal(&ctime, &fattr->cf_ctime);
86db0f1c07SPaulo Alcantara }
87db0f1c07SPaulo Alcantara 
cifs_open_data_reparse(struct cifs_open_info_data * data)88db0f1c07SPaulo Alcantara static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
89db0f1c07SPaulo Alcantara {
90db0f1c07SPaulo Alcantara 	struct smb2_file_all_info *fi = &data->fi;
91db0f1c07SPaulo Alcantara 	u32 attrs = le32_to_cpu(fi->Attributes);
92db0f1c07SPaulo Alcantara 	bool ret;
93db0f1c07SPaulo Alcantara 
94db0f1c07SPaulo Alcantara 	ret = data->reparse_point || (attrs & ATTR_REPARSE);
95db0f1c07SPaulo Alcantara 	if (ret)
96db0f1c07SPaulo Alcantara 		attrs |= ATTR_REPARSE;
97db0f1c07SPaulo Alcantara 	fi->Attributes = cpu_to_le32(attrs);
98db0f1c07SPaulo Alcantara 	return ret;
99db0f1c07SPaulo Alcantara }
100db0f1c07SPaulo Alcantara 
101db0f1c07SPaulo Alcantara bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
102db0f1c07SPaulo Alcantara 				 struct cifs_fattr *fattr,
103db0f1c07SPaulo Alcantara 				 struct cifs_open_info_data *data);
104db0f1c07SPaulo Alcantara int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
105db0f1c07SPaulo Alcantara 				struct dentry *dentry, struct cifs_tcon *tcon,
106db0f1c07SPaulo Alcantara 				const char *full_path, const char *symname);
107df0a8a19SPaulo Alcantara int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
108db0f1c07SPaulo Alcantara 		       struct dentry *dentry, struct cifs_tcon *tcon,
109db0f1c07SPaulo Alcantara 		       const char *full_path, umode_t mode, dev_t dev);
110db0f1c07SPaulo Alcantara int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb, struct kvec *rsp_iov,
111db0f1c07SPaulo Alcantara 			     struct cifs_open_info_data *data);
112db0f1c07SPaulo Alcantara 
113db0f1c07SPaulo Alcantara #endif /* _CIFS_REPARSE_H */
114