From: Chuck Lever Enable upper layers such as NFSD to retrieve case sensitivity information from file systems by adding a case_info field to struct file_kattr. Add vfs_get_case_info() as a convenience helper for kernel consumers. If a filesystem does not provide a fileattr_get hook, it returns the default POSIX behavior (case-sensitive, case-preserving), which is correct for the majority of Linux file systems implementations. Signed-off-by: Chuck Lever --- fs/file_attr.c | 31 +++++++++++++++++++++++++++++++ include/linux/fileattr.h | 23 +++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/fs/file_attr.c b/fs/file_attr.c index 1dcec88c0680..609e890b5101 100644 --- a/fs/file_attr.c +++ b/fs/file_attr.c @@ -94,6 +94,37 @@ int vfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) } EXPORT_SYMBOL(vfs_fileattr_get); +/** + * vfs_get_case_info - retrieve case sensitivity info for a filesystem + * @dentry: the object to retrieve from + * @case_info: pointer to store result + * + * Call i_op->fileattr_get() to retrieve case sensitivity information. + * If the filesystem does not provide a fileattr_get hook, return + * the default POSIX behavior (case-sensitive, case-preserving). + * + * Return: 0 on success, or a negative error on failure. + */ +int vfs_get_case_info(struct dentry *dentry, u32 *case_info) +{ + struct file_kattr fa = {}; + int error; + + /* Default: POSIX semantics (case-sensitive, case-preserving) */ + *case_info = FILEATTR_CASEFOLD_NONE | FILEATTR_CASE_PRESERVING; + + error = vfs_fileattr_get(dentry, &fa); + if (error == -ENOIOCTLCMD) + return 0; + if (error) + return error; + + if (fa.case_info) + *case_info = fa.case_info; + return 0; +} +EXPORT_SYMBOL(vfs_get_case_info); + static void fileattr_to_file_attr(const struct file_kattr *fa, struct file_attr *fattr) { diff --git a/include/linux/fileattr.h b/include/linux/fileattr.h index f89dcfad3f8f..55674d14f697 100644 --- a/include/linux/fileattr.h +++ b/include/linux/fileattr.h @@ -48,11 +48,33 @@ struct file_kattr { u32 fsx_nextents; /* nextents field value (get) */ u32 fsx_projid; /* project identifier (get/set) */ u32 fsx_cowextsize; /* CoW extsize field value (get/set)*/ + u32 case_info; /* case sensitivity behavior */ /* selectors: */ bool flags_valid:1; bool fsx_valid:1; }; +/* + * Values for file_kattr.case_info. + */ + +/* File name case is preserved at rest. */ +#define FILEATTR_CASE_PRESERVING 0x80000000 + +/* Values stored in the low-order byte */ +enum fileattr_case_folding { + /* Code points are compared directly with no case folding. */ + FILEATTR_CASEFOLD_NONE = 0, + + /* ASCII case-insensitive: A-Z are treated as a-z. */ + FILEATTR_CASEFOLD_ASCII, + + /* Unicode case-insensitive matching. */ + FILEATTR_CASEFOLD_UNICODE, +}; + +#define FILEATTR_CASEFOLD_TYPE 0x000000ff + int copy_fsxattr_to_user(const struct file_kattr *fa, struct fsxattr __user *ufa); void fileattr_fill_xflags(struct file_kattr *fa, u32 xflags); @@ -75,6 +97,7 @@ static inline bool fileattr_has_fsx(const struct file_kattr *fa) int vfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa); int vfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, struct file_kattr *fa); +int vfs_get_case_info(struct dentry *dentry, u32 *case_info); int ioctl_getflags(struct file *file, unsigned int __user *argp); int ioctl_setflags(struct file *file, unsigned int __user *argp); int ioctl_fsgetxattr(struct file *file, void __user *argp); -- 2.52.0