diff options
author | Jeff Layton <jlayton@redhat.com> | 2013-09-05 08:38:11 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2013-09-08 15:38:08 -0400 |
commit | ec71e0e15937ae3d0d8342b564c63649b23afa3a (patch) | |
tree | 7cd0cf52ae40771c27ed785c93d26ce316013ef7 /fs/cifs/dir.c | |
parent | c2ccf53dd0ddf0b48e68206c1abb99536851c7b2 (diff) |
cifs: convert case-insensitive dentry ops to use new case conversion routines
Have the case-insensitive d_compare and d_hash routines convert each
character in the filenames to wchar_t's and then use the new
cifs_toupper routine to convert those into uppercase.
With this scheme we should more closely emulate the case conversion that
the servers will do.
Reported-and-Tested-by: Jan-Marek Glogowski <glogow@fbihome.de>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/dir.c')
-rw-r--r-- | fs/cifs/dir.c | 58 |
1 files changed, 50 insertions, 8 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d62ce0d48141..d3e2eaa503a6 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "cifsproto.h" | 32 | #include "cifsproto.h" |
33 | #include "cifs_debug.h" | 33 | #include "cifs_debug.h" |
34 | #include "cifs_fs_sb.h" | 34 | #include "cifs_fs_sb.h" |
35 | #include "cifs_unicode.h" | ||
35 | 36 | ||
36 | static void | 37 | static void |
37 | renew_parental_timestamps(struct dentry *direntry) | 38 | renew_parental_timestamps(struct dentry *direntry) |
@@ -834,12 +835,17 @@ static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q) | |||
834 | { | 835 | { |
835 | struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls; | 836 | struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls; |
836 | unsigned long hash; | 837 | unsigned long hash; |
837 | int i; | 838 | wchar_t c; |
839 | int i, charlen; | ||
838 | 840 | ||
839 | hash = init_name_hash(); | 841 | hash = init_name_hash(); |
840 | for (i = 0; i < q->len; i++) | 842 | for (i = 0; i < q->len; i += charlen) { |
841 | hash = partial_name_hash(nls_tolower(codepage, q->name[i]), | 843 | charlen = codepage->char2uni(&q->name[i], q->len - i, &c); |
842 | hash); | 844 | /* error out if we can't convert the character */ |
845 | if (unlikely(charlen < 0)) | ||
846 | return charlen; | ||
847 | hash = partial_name_hash(cifs_toupper(c), hash); | ||
848 | } | ||
843 | q->hash = end_name_hash(hash); | 849 | q->hash = end_name_hash(hash); |
844 | 850 | ||
845 | return 0; | 851 | return 0; |
@@ -849,11 +855,47 @@ static int cifs_ci_compare(const struct dentry *parent, const struct dentry *den | |||
849 | unsigned int len, const char *str, const struct qstr *name) | 855 | unsigned int len, const char *str, const struct qstr *name) |
850 | { | 856 | { |
851 | struct nls_table *codepage = CIFS_SB(parent->d_sb)->local_nls; | 857 | struct nls_table *codepage = CIFS_SB(parent->d_sb)->local_nls; |
858 | wchar_t c1, c2; | ||
859 | int i, l1, l2; | ||
852 | 860 | ||
853 | if ((name->len == len) && | 861 | /* |
854 | (nls_strnicmp(codepage, name->name, str, len) == 0)) | 862 | * We make the assumption here that uppercase characters in the local |
855 | return 0; | 863 | * codepage are always the same length as their lowercase counterparts. |
856 | return 1; | 864 | * |
865 | * If that's ever not the case, then this will fail to match it. | ||
866 | */ | ||
867 | if (name->len != len) | ||
868 | return 1; | ||
869 | |||
870 | for (i = 0; i < len; i += l1) { | ||
871 | /* Convert characters in both strings to UTF-16. */ | ||
872 | l1 = codepage->char2uni(&str[i], len - i, &c1); | ||
873 | l2 = codepage->char2uni(&name->name[i], name->len - i, &c2); | ||
874 | |||
875 | /* | ||
876 | * If we can't convert either character, just declare it to | ||
877 | * be 1 byte long and compare the original byte. | ||
878 | */ | ||
879 | if (unlikely(l1 < 0 && l2 < 0)) { | ||
880 | if (str[i] != name->name[i]) | ||
881 | return 1; | ||
882 | l1 = 1; | ||
883 | continue; | ||
884 | } | ||
885 | |||
886 | /* | ||
887 | * Here, we again ass|u|me that upper/lowercase versions of | ||
888 | * a character are the same length in the local NLS. | ||
889 | */ | ||
890 | if (l1 != l2) | ||
891 | return 1; | ||
892 | |||
893 | /* Now compare uppercase versions of these characters */ | ||
894 | if (cifs_toupper(c1) != cifs_toupper(c2)) | ||
895 | return 1; | ||
896 | } | ||
897 | |||
898 | return 0; | ||
857 | } | 899 | } |
858 | 900 | ||
859 | const struct dentry_operations cifs_ci_dentry_ops = { | 901 | const struct dentry_operations cifs_ci_dentry_ops = { |