[PATCH] exfat: intorduce skip_stream_check mount opt
From: Yangtao Li
Date: Mon Jun 06 2022 - 22:50:13 EST
There are some files in my USB flash drive that can be recognized by
the Windows computer, but on Linux, only the existence of the file name
can be seen.
When executing ls command to view the file attributes or access, the file
does not exist. Therefore, when the current windows and linux drivers
access a file, there is a difference in the checking of the file metadata,
which leads to this situation.
(There is also a difference between traversing all children of the parent
directory and finding a child in the parent directory on linux.)
So, we introduce a new mount option that skips the check of the file stream
entry in exfat_find_dir_entry().
Signed-off-by: Yangtao Li <frank.li@xxxxxxxx>
---
fs/exfat/dir.c | 6 ++++--
fs/exfat/exfat_fs.h | 3 ++-
fs/exfat/super.c | 7 +++++++
3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c
index cb1c0d8c1714..4ea0077f2955 100644
--- a/fs/exfat/dir.c
+++ b/fs/exfat/dir.c
@@ -1013,6 +1013,7 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
}
if (entry_type == TYPE_STREAM) {
+ struct exfat_mount_options *opts = &sbi->options;
u16 name_hash;
if (step != DIRENT_STEP_STRM) {
@@ -1023,9 +1024,10 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
step = DIRENT_STEP_FILE;
name_hash = le16_to_cpu(
ep->dentry.stream.name_hash);
- if (p_uniname->name_hash == name_hash &&
+ if ((p_uniname->name_hash == name_hash &&
p_uniname->name_len ==
- ep->dentry.stream.name_len) {
+ ep->dentry.stream.name_len) ||
+ opts->skip_stream_check == 1) {
step = DIRENT_STEP_NAME;
order = 1;
name_len = 0;
diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index 1d6da61157c9..5cd00ac112d9 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -204,7 +204,8 @@ struct exfat_mount_options {
/* on error: continue, panic, remount-ro */
enum exfat_error_mode errors;
unsigned utf8:1, /* Use of UTF-8 character set */
- discard:1; /* Issue discard requests on deletions */
+ discard:1, /* Issue discard requests on deletions */
+ skip_stream_check:1; /* Skip stream entry check in exfat_find_dir_entry() */
int time_offset; /* Offset of timestamps from UTC (in minutes) */
};
diff --git a/fs/exfat/super.c b/fs/exfat/super.c
index 5539ffc20d16..e9c7df25f2b5 100644
--- a/fs/exfat/super.c
+++ b/fs/exfat/super.c
@@ -173,6 +173,8 @@ static int exfat_show_options(struct seq_file *m, struct dentry *root)
seq_puts(m, ",errors=remount-ro");
if (opts->discard)
seq_puts(m, ",discard");
+ if (opts->skip_stream_check)
+ seq_puts(m, ",skip_stream_check");
if (opts->time_offset)
seq_printf(m, ",time_offset=%d", opts->time_offset);
return 0;
@@ -216,6 +218,7 @@ enum {
Opt_charset,
Opt_errors,
Opt_discard,
+ Opt_skip_stream_check,
Opt_time_offset,
/* Deprecated options */
@@ -242,6 +245,7 @@ static const struct fs_parameter_spec exfat_parameters[] = {
fsparam_string("iocharset", Opt_charset),
fsparam_enum("errors", Opt_errors, exfat_param_enums),
fsparam_flag("discard", Opt_discard),
+ fsparam_flag("skip_stream_check", Opt_skip_stream_check),
fsparam_s32("time_offset", Opt_time_offset),
__fsparam(NULL, "utf8", Opt_utf8, fs_param_deprecated,
NULL),
@@ -296,6 +300,9 @@ static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param)
case Opt_discard:
opts->discard = 1;
break;
+ case Opt_skip_stream_check:
+ opts->skip_stream_check = 1;
+ break;
case Opt_time_offset:
/*
* Make the limit 24 just in case someone invents something
--
2.35.1