fat: Implement fileattr_get for case sensitivity

Report FAT's case sensitivity behavior via the FS_XFLAG_CASEFOLD
and FS_XFLAG_CASENONPRESERVING flags. FAT filesystems are
case-insensitive by default.

MSDOS supports a 'nocase' mount option that enables case-sensitive
behavior; check this option when reporting case sensitivity.

VFAT long filename entries preserve case; without VFAT, only
uppercased 8.3 short names are stored. MSDOS with 'nocase' also
preserves case since the name-formatting code skips upcasing when
'nocase' is set. Check both options when reporting case preservation.

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Roland Mainz <roland.mainz@nrubsig.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Link: https://patch.msgid.link/20260507-case-sensitivity-v14-3-e62cc8200435@oracle.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Chuck Lever
2026-05-07 04:52:56 -04:00
committed by Christian Brauner
parent 3035e44541
commit c92db2ca72
4 changed files with 41 additions and 0 deletions

View File

@@ -10,6 +10,8 @@
#include <linux/fs_context.h>
#include <linux/fs_parser.h>
struct file_kattr;
/*
* vfat shortname flags
*/
@@ -408,6 +410,7 @@ extern void fat_truncate_blocks(struct inode *inode, loff_t offset);
extern int fat_getattr(struct mnt_idmap *idmap,
const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags);
int fat_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
extern int fat_file_fsync(struct file *file, loff_t start, loff_t end,
int datasync);

View File

@@ -17,6 +17,7 @@
#include <linux/fsnotify.h>
#include <linux/security.h>
#include <linux/falloc.h>
#include <linux/fileattr.h>
#include "fat.h"
static long fat_fallocate(struct file *file, int mode,
@@ -398,6 +399,40 @@ void fat_truncate_blocks(struct inode *inode, loff_t offset)
fat_flush_inodes(inode->i_sb, inode, NULL);
}
int fat_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
{
struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
bool case_sensitive;
/*
* FAT filesystems are case-insensitive by default. VFAT
* becomes case-sensitive when mounted with 'check=strict',
* which installs vfat_dentry_ops. MSDOS has no such option;
* its 'nocase' mount option selects case-sensitive matching.
*
* VFAT long filename entries preserve case. Without VFAT, only
* uppercased 8.3 short names are stored. MSDOS with 'nocase'
* also preserves case.
*/
if (sbi->options.isvfat)
case_sensitive = sbi->options.name_check == 's';
else
case_sensitive = sbi->options.nocase;
if (!case_sensitive) {
fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
fa->flags |= FS_CASEFOLD_FL;
if (!sbi->options.isvfat)
fa->fsx_xflags |= FS_XFLAG_CASENONPRESERVING;
}
if (d_inode(dentry)->i_flags & S_IMMUTABLE) {
fa->fsx_xflags |= FS_XFLAG_IMMUTABLE;
fa->flags |= FS_IMMUTABLE_FL;
}
return 0;
}
EXPORT_SYMBOL_GPL(fat_fileattr_get);
int fat_getattr(struct mnt_idmap *idmap, const struct path *path,
struct kstat *stat, u32 request_mask, unsigned int flags)
{
@@ -575,5 +610,6 @@ EXPORT_SYMBOL_GPL(fat_setattr);
const struct inode_operations fat_file_inode_operations = {
.setattr = fat_setattr,
.getattr = fat_getattr,
.fileattr_get = fat_fileattr_get,
.update_time = fat_update_time,
};

View File

@@ -644,6 +644,7 @@ static const struct inode_operations msdos_dir_inode_operations = {
.rename = msdos_rename,
.setattr = fat_setattr,
.getattr = fat_getattr,
.fileattr_get = fat_fileattr_get,
.update_time = fat_update_time,
};

View File

@@ -1185,6 +1185,7 @@ static const struct inode_operations vfat_dir_inode_operations = {
.rename = vfat_rename2,
.setattr = fat_setattr,
.getattr = fat_getattr,
.fileattr_get = fat_fileattr_get,
.update_time = fat_update_time,
};