]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
fat: Implement fileattr_get for case sensitivity
authorChuck Lever <chuck.lever@oracle.com>
Thu, 7 May 2026 08:52:56 +0000 (04:52 -0400)
committerChristian Brauner <brauner@kernel.org>
Mon, 11 May 2026 14:50:28 +0000 (16:50 +0200)
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>
fs/fat/fat.h
fs/fat/file.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c

index 5a58f0bf8ce83dd510e1708bab2acac71ff6d2c6..99ed9228a677be754b815753ba9e5dbf82efd423 100644 (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);
 
index becccdd2e501a8adcd21121d122db96b186f4b94..37e7049b4c8c4497ba7cfabd2192bfb4840b5b3d 100644 (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,
 };
index 4cc65f330fb7ee89f69aa245d6d451c3bfc82dad..0fd2971ad4b13143a5b4fa1e1e403904fa6bf38a 100644 (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,
 };
 
index 918b3756674c3052c9f20be5ea4a8b7e2d9d943e..e909447873e364f6343f47d49192a6de5d81e58c 100644 (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,
 };