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

fs/ntfs3: Add option "nocase"

This commit adds mount option and additional functions.

Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>

+162 -1
+1 -1
fs/ntfs3/index.c
··· 47 47 if (l2 < fsize2) 48 48 return -1; 49 49 50 - both_case = f2->type != FILE_NAME_DOS /*&& !sbi->options.nocase*/; 50 + both_case = f2->type != FILE_NAME_DOS && !sbi->options->nocase; 51 51 if (!l1) { 52 52 const struct le_str *s2 = (struct le_str *)&f2->name_len; 53 53
+139
fs/ntfs3/namei.c
··· 7 7 8 8 #include <linux/fs.h> 9 9 #include <linux/nls.h> 10 + #include <linux/ctype.h> 10 11 11 12 #include "debug.h" 12 13 #include "ntfs.h" ··· 356 355 return ERR_PTR(-ENOENT); 357 356 } 358 357 358 + /* 359 + * dentry_operations::d_hash 360 + */ 361 + static int ntfs_d_hash(const struct dentry *dentry, struct qstr *name) 362 + { 363 + struct ntfs_sb_info *sbi; 364 + const char *n = name->name; 365 + unsigned int len = name->len; 366 + unsigned long hash; 367 + struct cpu_str *uni; 368 + unsigned int c; 369 + int err; 370 + 371 + /* First try fast implementation. */ 372 + hash = init_name_hash(dentry); 373 + 374 + for (;;) { 375 + if (!len--) { 376 + name->hash = end_name_hash(hash); 377 + return 0; 378 + } 379 + 380 + c = *n++; 381 + if (c >= 0x80) 382 + break; 383 + 384 + hash = partial_name_hash(toupper(c), hash); 385 + } 386 + 387 + /* 388 + * Try slow way with current upcase table 389 + */ 390 + uni = __getname(); 391 + if (!uni) 392 + return -ENOMEM; 393 + 394 + sbi = dentry->d_sb->s_fs_info; 395 + 396 + err = ntfs_nls_to_utf16(sbi, name->name, name->len, uni, NTFS_NAME_LEN, 397 + UTF16_HOST_ENDIAN); 398 + if (err < 0) 399 + goto out; 400 + 401 + if (!err) { 402 + err = -EINVAL; 403 + goto out; 404 + } 405 + 406 + hash = ntfs_names_hash(uni->name, uni->len, sbi->upcase, 407 + init_name_hash(dentry)); 408 + name->hash = end_name_hash(hash); 409 + err = 0; 410 + 411 + out: 412 + __putname(uni); 413 + return err; 414 + } 415 + 416 + /* 417 + * dentry_operations::d_compare 418 + */ 419 + static int ntfs_d_compare(const struct dentry *dentry, unsigned int len1, 420 + const char *str, const struct qstr *name) 421 + { 422 + struct ntfs_sb_info *sbi; 423 + int ret; 424 + const char *n1 = str; 425 + const char *n2 = name->name; 426 + unsigned int len2 = name->len; 427 + unsigned int lm = min(len1, len2); 428 + unsigned char c1, c2; 429 + struct cpu_str *uni1, *uni2; 430 + 431 + /* First try fast implementation. */ 432 + for (;;) { 433 + if (!lm--) { 434 + ret = len1 == len2 ? 0 : 1; 435 + goto out; 436 + } 437 + 438 + if ((c1 = *n1++) == (c2 = *n2++)) 439 + continue; 440 + 441 + if (c1 >= 0x80 || c2 >= 0x80) 442 + break; 443 + 444 + if (toupper(c1) != toupper(c2)) { 445 + ret = 1; 446 + goto out; 447 + } 448 + } 449 + 450 + /* 451 + * Try slow way with current upcase table 452 + */ 453 + sbi = dentry->d_sb->s_fs_info; 454 + uni1 = __getname(); 455 + if (!uni1) 456 + return -ENOMEM; 457 + 458 + ret = ntfs_nls_to_utf16(sbi, str, len1, uni1, NTFS_NAME_LEN, 459 + UTF16_HOST_ENDIAN); 460 + if (ret < 0) 461 + goto out; 462 + 463 + if (!ret) { 464 + ret = -EINVAL; 465 + goto out; 466 + } 467 + 468 + uni2 = Add2Ptr(uni1, 2048); 469 + 470 + ret = ntfs_nls_to_utf16(sbi, name->name, name->len, uni2, NTFS_NAME_LEN, 471 + UTF16_HOST_ENDIAN); 472 + if (ret < 0) 473 + goto out; 474 + 475 + if (!ret) { 476 + ret = -EINVAL; 477 + goto out; 478 + } 479 + 480 + ret = !ntfs_cmp_names(uni1->name, uni1->len, uni2->name, uni2->len, 481 + sbi->upcase, false) 482 + ? 0 483 + : 1; 484 + 485 + out: 486 + __putname(uni1); 487 + return ret; 488 + } 489 + 359 490 // clang-format off 360 491 const struct inode_operations ntfs_dir_inode_operations = { 361 492 .lookup = ntfs_lookup, ··· 515 382 .get_acl = ntfs_get_acl, 516 383 .set_acl = ntfs_set_acl, 517 384 }; 385 + 386 + const struct dentry_operations ntfs_dentry_ops = { 387 + .d_hash = ntfs_d_hash, 388 + .d_compare = ntfs_d_compare, 389 + }; 390 + 518 391 // clang-format on
+4
fs/ntfs3/ntfs_fs.h
··· 101 101 unsigned force : 1; /* RW mount dirty volume. */ 102 102 unsigned noacsrules : 1; /* Exclude acs rules. */ 103 103 unsigned prealloc : 1; /* Preallocate space when file is growing. */ 104 + unsigned nocase : 1; /* case insensitive. */ 104 105 }; 105 106 106 107 /* Special value to unpack and deallocate. */ ··· 722 721 723 722 extern const struct inode_operations ntfs_dir_inode_operations; 724 723 extern const struct inode_operations ntfs_special_inode_operations; 724 + extern const struct dentry_operations ntfs_dentry_ops; 725 725 726 726 /* Globals from record.c */ 727 727 int mi_get(struct ntfs_sb_info *sbi, CLST rno, struct mft_inode **mi); ··· 842 840 const u16 *upcase, bool bothcase); 843 841 int ntfs_cmp_names_cpu(const struct cpu_str *uni1, const struct le_str *uni2, 844 842 const u16 *upcase, bool bothcase); 843 + unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase, 844 + unsigned long hash); 845 845 846 846 /* globals from xattr.c */ 847 847 #ifdef CONFIG_NTFS3_FS_POSIX_ACL
+6
fs/ntfs3/super.c
··· 253 253 Opt_iocharset, 254 254 Opt_prealloc, 255 255 Opt_noacsrules, 256 + Opt_nocase, 256 257 Opt_err, 257 258 }; 258 259 ··· 273 272 fsparam_flag_no("showmeta", Opt_showmeta), 274 273 fsparam_flag_no("prealloc", Opt_prealloc), 275 274 fsparam_flag_no("acsrules", Opt_noacsrules), 275 + fsparam_flag_no("nocase", Opt_nocase), 276 276 fsparam_string("iocharset", Opt_iocharset), 277 277 {} 278 278 }; ··· 384 382 break; 385 383 case Opt_noacsrules: 386 384 opts->noacsrules = result.negated ? 1 : 0; 385 + break; 386 + case Opt_nocase: 387 + opts->nocase = result.negated ? 1 : 0; 387 388 break; 388 389 default: 389 390 /* Should not be here unless we forget add case. */ ··· 941 936 sb->s_export_op = &ntfs_export_ops; 942 937 sb->s_time_gran = NTFS_TIME_GRAN; // 100 nsec 943 938 sb->s_xattr = ntfs_xattr_handlers; 939 + sb->s_d_op = sbi->options->nocase ? &ntfs_dentry_ops : NULL; 944 940 945 941 sbi->options->nls = ntfs_load_nls(sbi->options->nls_name); 946 942 if (IS_ERR(sbi->options->nls)) {
+12
fs/ntfs3/upcase.c
··· 102 102 diff2 = l1 - l2; 103 103 return diff2 ? diff2 : diff1; 104 104 } 105 + 106 + /* Helper function for ntfs_d_hash. */ 107 + unsigned long ntfs_names_hash(const u16 *name, size_t len, const u16 *upcase, 108 + unsigned long hash) 109 + { 110 + while (len--) { 111 + unsigned int c = upcase_unicode_char(upcase, *name++); 112 + hash = partial_name_hash(c, hash); 113 + } 114 + 115 + return hash; 116 + }