mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
fs/ntfs3: Add option "nocase"
This commit adds mount option and additional functions. Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
This commit is contained in:
parent
ae6b47b565
commit
a3a956c78e
@ -47,7 +47,7 @@ static int cmp_fnames(const void *key1, size_t l1, const void *key2, size_t l2,
|
||||
if (l2 < fsize2)
|
||||
return -1;
|
||||
|
||||
both_case = f2->type != FILE_NAME_DOS /*&& !sbi->options.nocase*/;
|
||||
both_case = f2->type != FILE_NAME_DOS && !sbi->options->nocase;
|
||||
if (!l1) {
|
||||
const struct le_str *s2 = (struct le_str *)&f2->name_len;
|
||||
|
||||
|
139
fs/ntfs3/namei.c
139
fs/ntfs3/namei.c
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "ntfs.h"
|
||||
@ -355,6 +356,138 @@ struct dentry *ntfs3_get_parent(struct dentry *child)
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
/*
|
||||
* dentry_operations::d_hash
|
||||
*/
|
||||
static int ntfs_d_hash(const struct dentry *dentry, struct qstr *name)
|
||||
{
|
||||
struct ntfs_sb_info *sbi;
|
||||
const char *n = name->name;
|
||||
unsigned int len = name->len;
|
||||
unsigned long hash;
|
||||
struct cpu_str *uni;
|
||||
unsigned int c;
|
||||
int err;
|
||||
|
||||
/* First try fast implementation. */
|
||||
hash = init_name_hash(dentry);
|
||||
|
||||
for (;;) {
|
||||
if (!len--) {
|
||||
name->hash = end_name_hash(hash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
c = *n++;
|
||||
if (c >= 0x80)
|
||||
break;
|
||||
|
||||
hash = partial_name_hash(toupper(c), hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try slow way with current upcase table
|
||||
*/
|
||||
uni = __getname();
|
||||
if (!uni)
|
||||
return -ENOMEM;
|
||||
|
||||
sbi = dentry->d_sb->s_fs_info;
|
||||
|
||||
err = ntfs_nls_to_utf16(sbi, name->name, name->len, uni, NTFS_NAME_LEN,
|
||||
UTF16_HOST_ENDIAN);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
if (!err) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hash = ntfs_names_hash(uni->name, uni->len, sbi->upcase,
|
||||
init_name_hash(dentry));
|
||||
name->hash = end_name_hash(hash);
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
__putname(uni);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* dentry_operations::d_compare
|
||||
*/
|
||||
static int ntfs_d_compare(const struct dentry *dentry, unsigned int len1,
|
||||
const char *str, const struct qstr *name)
|
||||
{
|
||||
struct ntfs_sb_info *sbi;
|
||||
int ret;
|
||||
const char *n1 = str;
|
||||
const char *n2 = name->name;
|
||||
unsigned int len2 = name->len;
|
||||
unsigned int lm = min(len1, len2);
|
||||
unsigned char c1, c2;
|
||||
struct cpu_str *uni1, *uni2;
|
||||
|
||||
/* First try fast implementation. */
|
||||
for (;;) {
|
||||
if (!lm--) {
|
||||
ret = len1 == len2 ? 0 : 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((c1 = *n1++) == (c2 = *n2++))
|
||||
continue;
|
||||
|
||||
if (c1 >= 0x80 || c2 >= 0x80)
|
||||
break;
|
||||
|
||||
if (toupper(c1) != toupper(c2)) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try slow way with current upcase table
|
||||
*/
|
||||
sbi = dentry->d_sb->s_fs_info;
|
||||
uni1 = __getname();
|
||||
if (!uni1)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ntfs_nls_to_utf16(sbi, str, len1, uni1, NTFS_NAME_LEN,
|
||||
UTF16_HOST_ENDIAN);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (!ret) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
uni2 = Add2Ptr(uni1, 2048);
|
||||
|
||||
ret = ntfs_nls_to_utf16(sbi, name->name, name->len, uni2, NTFS_NAME_LEN,
|
||||
UTF16_HOST_ENDIAN);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (!ret) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = !ntfs_cmp_names(uni1->name, uni1->len, uni2->name, uni2->len,
|
||||
sbi->upcase, false)
|
||||
? 0
|
||||
: 1;
|
||||
|
||||
out:
|
||||
__putname(uni1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
const struct inode_operations ntfs_dir_inode_operations = {
|
||||
.lookup = ntfs_lookup,
|
||||
@ -382,4 +515,10 @@ const struct inode_operations ntfs_special_inode_operations = {
|
||||
.get_acl = ntfs_get_acl,
|
||||
.set_acl = ntfs_set_acl,
|
||||
};
|
||||
|
||||
const struct dentry_operations ntfs_dentry_ops = {
|
||||
.d_hash = ntfs_d_hash,
|
||||
.d_compare = ntfs_d_compare,
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
@ -101,6 +101,7 @@ struct ntfs_mount_options {
|
||||
unsigned force : 1; /* RW mount dirty volume. */
|
||||
unsigned noacsrules : 1; /* Exclude acs rules. */
|
||||
unsigned prealloc : 1; /* Preallocate space when file is growing. */
|
||||
unsigned nocase : 1; /* case insensitive. */
|
||||
};
|
||||
|
||||
/* Special value to unpack and deallocate. */
|
||||
@ -721,6 +722,7 @@ struct dentry *ntfs3_get_parent(struct dentry *child);
|
||||
|
||||
extern const struct inode_operations ntfs_dir_inode_operations;
|
||||
extern const struct inode_operations ntfs_special_inode_operations;
|
||||
extern const struct dentry_operations ntfs_dentry_ops;
|
||||
|
||||
/* Globals from record.c */
|
||||
int mi_get(struct ntfs_sb_info *sbi, CLST rno, struct mft_inode **mi);
|
||||
@ -840,6 +842,8 @@ int ntfs_cmp_names(const __le16 *s1, size_t l1, const __le16 *s2, size_t l2,
|
||||
const u16 *upcase, bool bothcase);
|
||||
int ntfs_cmp_names_cpu(const struct cpu_str *uni1, const struct le_str *uni2,
|
||||
const u16 *upcase, bool bothcase);
|
||||
unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase,
|
||||
unsigned long hash);
|
||||
|
||||
/* globals from xattr.c */
|
||||
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
|
||||
|
@ -253,6 +253,7 @@ enum Opt {
|
||||
Opt_iocharset,
|
||||
Opt_prealloc,
|
||||
Opt_noacsrules,
|
||||
Opt_nocase,
|
||||
Opt_err,
|
||||
};
|
||||
|
||||
@ -272,6 +273,7 @@ static const struct fs_parameter_spec ntfs_fs_parameters[] = {
|
||||
fsparam_flag_no("showmeta", Opt_showmeta),
|
||||
fsparam_flag_no("prealloc", Opt_prealloc),
|
||||
fsparam_flag_no("acsrules", Opt_noacsrules),
|
||||
fsparam_flag_no("nocase", Opt_nocase),
|
||||
fsparam_string("iocharset", Opt_iocharset),
|
||||
{}
|
||||
};
|
||||
@ -383,6 +385,9 @@ static int ntfs_fs_parse_param(struct fs_context *fc,
|
||||
case Opt_noacsrules:
|
||||
opts->noacsrules = result.negated ? 1 : 0;
|
||||
break;
|
||||
case Opt_nocase:
|
||||
opts->nocase = result.negated ? 1 : 0;
|
||||
break;
|
||||
default:
|
||||
/* Should not be here unless we forget add case. */
|
||||
return -EINVAL;
|
||||
@ -936,6 +941,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
sb->s_export_op = &ntfs_export_ops;
|
||||
sb->s_time_gran = NTFS_TIME_GRAN; // 100 nsec
|
||||
sb->s_xattr = ntfs_xattr_handlers;
|
||||
sb->s_d_op = sbi->options->nocase ? &ntfs_dentry_ops : NULL;
|
||||
|
||||
sbi->options->nls = ntfs_load_nls(sbi->options->nls_name);
|
||||
if (IS_ERR(sbi->options->nls)) {
|
||||
|
@ -102,3 +102,15 @@ case_insentive:
|
||||
diff2 = l1 - l2;
|
||||
return diff2 ? diff2 : diff1;
|
||||
}
|
||||
|
||||
/* Helper function for ntfs_d_hash. */
|
||||
unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase,
|
||||
unsigned long hash)
|
||||
{
|
||||
while (len--) {
|
||||
unsigned int c = upcase_unicode_char(upcase, *name++);
|
||||
hash = partial_name_hash(c, hash);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user