Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Jeff Layton and committed by
Steve French
ec71e0e1 c2ccf53d

+50 -8
+50 -8
fs/cifs/dir.c
··· 32 32 #include "cifsproto.h" 33 33 #include "cifs_debug.h" 34 34 #include "cifs_fs_sb.h" 35 + #include "cifs_unicode.h" 35 36 36 37 static void 37 38 renew_parental_timestamps(struct dentry *direntry) ··· 835 834 { 836 835 struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls; 837 836 unsigned long hash; 838 - int i; 837 + wchar_t c; 838 + int i, charlen; 839 839 840 840 hash = init_name_hash(); 841 - for (i = 0; i < q->len; i++) 842 - hash = partial_name_hash(nls_tolower(codepage, q->name[i]), 843 - hash); 841 + for (i = 0; i < q->len; i += charlen) { 842 + charlen = codepage->char2uni(&q->name[i], q->len - i, &c); 843 + /* error out if we can't convert the character */ 844 + if (unlikely(charlen < 0)) 845 + return charlen; 846 + hash = partial_name_hash(cifs_toupper(c), hash); 847 + } 844 848 q->hash = end_name_hash(hash); 845 849 846 850 return 0; ··· 855 849 unsigned int len, const char *str, const struct qstr *name) 856 850 { 857 851 struct nls_table *codepage = CIFS_SB(parent->d_sb)->local_nls; 852 + wchar_t c1, c2; 853 + int i, l1, l2; 858 854 859 - if ((name->len == len) && 860 - (nls_strnicmp(codepage, name->name, str, len) == 0)) 861 - return 0; 862 - return 1; 855 + /* 856 + * We make the assumption here that uppercase characters in the local 857 + * codepage are always the same length as their lowercase counterparts. 858 + * 859 + * If that's ever not the case, then this will fail to match it. 860 + */ 861 + if (name->len != len) 862 + return 1; 863 + 864 + for (i = 0; i < len; i += l1) { 865 + /* Convert characters in both strings to UTF-16. */ 866 + l1 = codepage->char2uni(&str[i], len - i, &c1); 867 + l2 = codepage->char2uni(&name->name[i], name->len - i, &c2); 868 + 869 + /* 870 + * If we can't convert either character, just declare it to 871 + * be 1 byte long and compare the original byte. 872 + */ 873 + if (unlikely(l1 < 0 && l2 < 0)) { 874 + if (str[i] != name->name[i]) 875 + return 1; 876 + l1 = 1; 877 + continue; 878 + } 879 + 880 + /* 881 + * Here, we again ass|u|me that upper/lowercase versions of 882 + * a character are the same length in the local NLS. 883 + */ 884 + if (l1 != l2) 885 + return 1; 886 + 887 + /* Now compare uppercase versions of these characters */ 888 + if (cifs_toupper(c1) != cifs_toupper(c2)) 889 + return 1; 890 + } 891 + 892 + return 0; 863 893 } 864 894 865 895 const struct dentry_operations cifs_ci_dentry_ops = {