Commit ad57a102 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'exfat-for-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat

Pull exfat update from Namjae Jeon:
 "Bug fixes:
   - Fix memory leak on mount failure with iocharset= option
   - Fix incorrect update of stream entry
   - Fix cluster range validation error

  Clean-ups:
   - Remove unused code and unneeded assignment
   - Rename variables in exfat structure as specification
   - Reorganize boot sector analysis code
   - Simplify exfat_utf8_d_hash and exfat_utf8_d_cmp()
   - Optimize exfat entry cache functions
   - Improve wording of EXFAT_DEFAULT_IOCHARSET config option

 New Feature:
   - Add boot region verification"

* tag 'exfat-for-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
  exfat: Fix potential use after free in exfat_load_upcase_table()
  exfat: fix range validation error in alloc and free cluster
  exfat: fix incorrect update of stream entry in __exfat_truncate()
  exfat: fix memory leak in exfat_parse_param()
  exfat: remove unnecessary reassignment of p_uniname->name_len
  exfat: standardize checksum calculation
  exfat: add boot region verification
  exfat: separate the boot sector analysis
  exfat: redefine PBR as boot_sector
  exfat: optimize dir-cache
  exfat: replace 'time_ms' with 'time_cs'
  exfat: remove the assignment of 0 to bool variable
  exfat: Remove unused functions exfat_high_surrogate() and exfat_low_surrogate()
  exfat: Simplify exfat_utf8_d_hash() for code points above U+FFFF
  exfat: Improve wording of EXFAT_DEFAULT_IOCHARSET config option
  exfat: Use a more common logging style
  exfat: Simplify exfat_utf8_d_cmp() for code points above U+FFFF
parents 3beff76b fc961522
...@@ -16,6 +16,7 @@ config EXFAT_DEFAULT_IOCHARSET ...@@ -16,6 +16,7 @@ config EXFAT_DEFAULT_IOCHARSET
depends on EXFAT_FS depends on EXFAT_FS
help help
Set this to the default input/output character set to use for Set this to the default input/output character set to use for
converting between the encoding is used for user visible filename and converting between the encoding that is used for user visible
UTF-16 character that exfat filesystem use, and can be overridden with filenames and the UTF-16 character encoding that the exFAT
the "iocharset" mount option for exFAT filesystems. filesystem uses. This can be overridden with the "iocharset" mount
option for the exFAT filesystems.
...@@ -58,9 +58,8 @@ static int exfat_allocate_bitmap(struct super_block *sb, ...@@ -58,9 +58,8 @@ static int exfat_allocate_bitmap(struct super_block *sb,
need_map_size = ((EXFAT_DATA_CLUSTER_COUNT(sbi) - 1) / BITS_PER_BYTE) need_map_size = ((EXFAT_DATA_CLUSTER_COUNT(sbi) - 1) / BITS_PER_BYTE)
+ 1; + 1;
if (need_map_size != map_size) { if (need_map_size != map_size) {
exfat_msg(sb, KERN_ERR, exfat_err(sb, "bogus allocation bitmap size(need : %u, cur : %lld)",
"bogus allocation bitmap size(need : %u, cur : %lld)", need_map_size, map_size);
need_map_size, map_size);
/* /*
* Only allowed when bogus allocation * Only allowed when bogus allocation
* bitmap size is large * bitmap size is large
...@@ -192,8 +191,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu) ...@@ -192,8 +191,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
(1 << sbi->sect_per_clus_bits), GFP_NOFS, 0); (1 << sbi->sect_per_clus_bits), GFP_NOFS, 0);
if (ret_discard == -EOPNOTSUPP) { if (ret_discard == -EOPNOTSUPP) {
exfat_msg(sb, KERN_ERR, exfat_err(sb, "discard not supported by device, disabling");
"discard not supported by device, disabling");
opts->discard = 0; opts->discard = 0;
} }
} }
......
This diff is collapsed.
...@@ -71,10 +71,8 @@ enum { ...@@ -71,10 +71,8 @@ enum {
#define MAX_NAME_LENGTH 255 /* max len of file name excluding NULL */ #define MAX_NAME_LENGTH 255 /* max len of file name excluding NULL */
#define MAX_VFSNAME_BUF_SIZE ((MAX_NAME_LENGTH + 1) * MAX_CHARSET_SIZE) #define MAX_VFSNAME_BUF_SIZE ((MAX_NAME_LENGTH + 1) * MAX_CHARSET_SIZE)
#define FAT_CACHE_SIZE 128 /* Enough size to hold 256 dentry (even 512 Byte sector) */
#define FAT_CACHE_HASH_SIZE 64 #define DIR_CACHE_SIZE (256*sizeof(struct exfat_dentry)/512+1)
#define BUF_CACHE_SIZE 256
#define BUF_CACHE_HASH_SIZE 64
#define EXFAT_HINT_NONE -1 #define EXFAT_HINT_NONE -1
#define EXFAT_MIN_SUBDIR 2 #define EXFAT_MIN_SUBDIR 2
...@@ -139,7 +137,7 @@ struct exfat_dentry_namebuf { ...@@ -139,7 +137,7 @@ struct exfat_dentry_namebuf {
struct exfat_uni_name { struct exfat_uni_name {
/* +3 for null and for converting */ /* +3 for null and for converting */
unsigned short name[MAX_NAME_LENGTH + 3]; unsigned short name[MAX_NAME_LENGTH + 3];
unsigned short name_hash; u16 name_hash;
unsigned char name_len; unsigned char name_len;
}; };
...@@ -170,14 +168,12 @@ struct exfat_hint { ...@@ -170,14 +168,12 @@ struct exfat_hint {
}; };
struct exfat_entry_set_cache { struct exfat_entry_set_cache {
/* sector number that contains file_entry */ struct super_block *sb;
sector_t sector; bool modified;
/* byte offset in the sector */ unsigned int start_off;
unsigned int offset; int num_bh;
/* flag in stream entry. 01 for cluster chain, 03 for contig. */ struct buffer_head *bh[DIR_CACHE_SIZE];
int alloc_flag;
unsigned int num_entries; unsigned int num_entries;
struct exfat_dentry entries[];
}; };
struct exfat_dir_entry { struct exfat_dir_entry {
...@@ -231,7 +227,7 @@ struct exfat_sb_info { ...@@ -231,7 +227,7 @@ struct exfat_sb_info {
unsigned int root_dir; /* root dir cluster */ unsigned int root_dir; /* root dir cluster */
unsigned int dentries_per_clu; /* num of dentries per cluster */ unsigned int dentries_per_clu; /* num of dentries per cluster */
unsigned int vol_flag; /* volume dirty flag */ unsigned int vol_flag; /* volume dirty flag */
struct buffer_head *pbr_bh; /* buffer_head of PBR sector */ struct buffer_head *boot_bh; /* buffer_head of BOOT sector */
unsigned int map_clu; /* allocation bitmap start cluster */ unsigned int map_clu; /* allocation bitmap start cluster */
unsigned int map_sectors; /* num of allocation bitmap sectors */ unsigned int map_sectors; /* num of allocation bitmap sectors */
...@@ -451,8 +447,7 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir, ...@@ -451,8 +447,7 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir,
int entry, int order, int num_entries); int entry, int order, int num_entries);
int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir, int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
int entry); int entry);
int exfat_update_dir_chksum_with_entry_set(struct super_block *sb, void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es);
struct exfat_entry_set_cache *es, int sync);
int exfat_calc_num_entries(struct exfat_uni_name *p_uniname); int exfat_calc_num_entries(struct exfat_uni_name *p_uniname);
int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei, int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname, struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
...@@ -463,9 +458,11 @@ int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir, ...@@ -463,9 +458,11 @@ int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir,
struct exfat_dentry *exfat_get_dentry(struct super_block *sb, struct exfat_dentry *exfat_get_dentry(struct super_block *sb,
struct exfat_chain *p_dir, int entry, struct buffer_head **bh, struct exfat_chain *p_dir, int entry, struct buffer_head **bh,
sector_t *sector); sector_t *sector);
struct exfat_dentry *exfat_get_dentry_cached(struct exfat_entry_set_cache *es,
int num);
struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb, struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,
struct exfat_chain *p_dir, int entry, unsigned int type, struct exfat_chain *p_dir, int entry, unsigned int type);
struct exfat_dentry **file_ep); void exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync);
int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir); int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir);
/* inode.c */ /* inode.c */
...@@ -492,8 +489,6 @@ int exfat_nls_to_utf16(struct super_block *sb, ...@@ -492,8 +489,6 @@ int exfat_nls_to_utf16(struct super_block *sb,
struct exfat_uni_name *uniname, int *p_lossy); struct exfat_uni_name *uniname, int *p_lossy);
int exfat_create_upcase_table(struct super_block *sb); int exfat_create_upcase_table(struct super_block *sb);
void exfat_free_upcase_table(struct exfat_sb_info *sbi); void exfat_free_upcase_table(struct exfat_sb_info *sbi);
unsigned short exfat_high_surrogate(unicode_t u);
unsigned short exfat_low_surrogate(unicode_t u);
/* exfat/misc.c */ /* exfat/misc.c */
void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
...@@ -505,13 +500,20 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) ...@@ -505,13 +500,20 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
fmt, ## args) fmt, ## args)
void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...) void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...)
__printf(3, 4) __cold; __printf(3, 4) __cold;
#define exfat_err(sb, fmt, ...) \
exfat_msg(sb, KERN_ERR, fmt, ##__VA_ARGS__)
#define exfat_warn(sb, fmt, ...) \
exfat_msg(sb, KERN_WARNING, fmt, ##__VA_ARGS__)
#define exfat_info(sb, fmt, ...) \
exfat_msg(sb, KERN_INFO, fmt, ##__VA_ARGS__)
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 tz, __le16 time, __le16 date, u8 time_ms); u8 tz, __le16 time, __le16 date, u8 time_cs);
void exfat_truncate_atime(struct timespec64 *ts); void exfat_truncate_atime(struct timespec64 *ts);
void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 *tz, __le16 *time, __le16 *date, u8 *time_ms); u8 *tz, __le16 *time, __le16 *date, u8 *time_cs);
unsigned short exfat_calc_chksum_2byte(void *data, int len, u16 exfat_calc_chksum16(void *data, int len, u16 chksum, int type);
unsigned short chksum, int type); u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type);
void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync); void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync);
void exfat_chain_set(struct exfat_chain *ec, unsigned int dir, void exfat_chain_set(struct exfat_chain *ec, unsigned int dir,
unsigned int size, unsigned char flags); unsigned int size, unsigned char flags);
......
...@@ -8,12 +8,15 @@ ...@@ -8,12 +8,15 @@
#include <linux/types.h> #include <linux/types.h>
#define PBR_SIGNATURE 0xAA55 #define BOOT_SIGNATURE 0xAA55
#define EXBOOT_SIGNATURE 0xAA550000
#define STR_EXFAT "EXFAT " /* size should be 8 */
#define EXFAT_MAX_FILE_LEN 255 #define EXFAT_MAX_FILE_LEN 255
#define VOL_CLEAN 0x0000 #define VOL_CLEAN 0x0000
#define VOL_DIRTY 0x0002 #define VOL_DIRTY 0x0002
#define ERR_MEDIUM 0x0004
#define EXFAT_EOF_CLUSTER 0xFFFFFFFFu #define EXFAT_EOF_CLUSTER 0xFFFFFFFFu
#define EXFAT_BAD_CLUSTER 0xFFFFFFF7u #define EXFAT_BAD_CLUSTER 0xFFFFFFF7u
...@@ -55,7 +58,7 @@ ...@@ -55,7 +58,7 @@
/* checksum types */ /* checksum types */
#define CS_DIR_ENTRY 0 #define CS_DIR_ENTRY 0
#define CS_PBR_SECTOR 1 #define CS_BOOT_SECTOR 1
#define CS_DEFAULT 2 #define CS_DEFAULT 2
/* file attributes */ /* file attributes */
...@@ -69,57 +72,35 @@ ...@@ -69,57 +72,35 @@
#define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \ #define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \
ATTR_SUBDIR | ATTR_ARCHIVE) ATTR_SUBDIR | ATTR_ARCHIVE)
#define PBR64_JUMP_BOOT_LEN 3 #define BOOTSEC_JUMP_BOOT_LEN 3
#define PBR64_OEM_NAME_LEN 8 #define BOOTSEC_FS_NAME_LEN 8
#define PBR64_RESERVED_LEN 53 #define BOOTSEC_OLDBPB_LEN 53
#define EXFAT_FILE_NAME_LEN 15 #define EXFAT_FILE_NAME_LEN 15
/* EXFAT BIOS parameter block (64 bytes) */ /* EXFAT: Main and Backup Boot Sector (512 bytes) */
struct bpb64 { struct boot_sector {
__u8 jmp_boot[PBR64_JUMP_BOOT_LEN]; __u8 jmp_boot[BOOTSEC_JUMP_BOOT_LEN];
__u8 oem_name[PBR64_OEM_NAME_LEN]; __u8 fs_name[BOOTSEC_FS_NAME_LEN];
__u8 res_zero[PBR64_RESERVED_LEN]; __u8 must_be_zero[BOOTSEC_OLDBPB_LEN];
} __packed; __le64 partition_offset;
__le64 vol_length;
/* EXFAT EXTEND BIOS parameter block (56 bytes) */ __le32 fat_offset;
struct bsx64 { __le32 fat_length;
__le64 vol_offset; __le32 clu_offset;
__le64 vol_length; __le32 clu_count;
__le32 fat_offset; __le32 root_cluster;
__le32 fat_length; __le32 vol_serial;
__le32 clu_offset; __u8 fs_revision[2];
__le32 clu_count; __le16 vol_flags;
__le32 root_cluster; __u8 sect_size_bits;
__le32 vol_serial; __u8 sect_per_clus_bits;
__u8 fs_version[2]; __u8 num_fats;
__le16 vol_flags; __u8 drv_sel;
__u8 sect_size_bits; __u8 percent_in_use;
__u8 sect_per_clus_bits; __u8 reserved[7];
__u8 num_fats; __u8 boot_code[390];
__u8 phy_drv_no; __le16 signature;
__u8 perc_in_use;
__u8 reserved2[7];
} __packed;
/* EXFAT PBR[BPB+BSX] (120 bytes) */
struct pbr64 {
struct bpb64 bpb;
struct bsx64 bsx;
} __packed;
/* Common PBR[Partition Boot Record] (512 bytes) */
struct pbr {
union {
__u8 raw[64];
struct bpb64 f64;
} bpb;
union {
__u8 raw[56];
struct bsx64 f64;
} bsx;
__u8 boot_code[390];
__le16 signature;
} __packed; } __packed;
struct exfat_dentry { struct exfat_dentry {
...@@ -136,8 +117,8 @@ struct exfat_dentry { ...@@ -136,8 +117,8 @@ struct exfat_dentry {
__le16 modify_date; __le16 modify_date;
__le16 access_time; __le16 access_time;
__le16 access_date; __le16 access_date;
__u8 create_time_ms; __u8 create_time_cs;
__u8 modify_time_ms; __u8 modify_time_cs;
__u8 create_tz; __u8 create_tz;
__u8 modify_tz; __u8 modify_tz;
__u8 access_tz; __u8 access_tz;
......
...@@ -169,9 +169,8 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) ...@@ -169,9 +169,8 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
return 0; return 0;
/* check cluster validation */ /* check cluster validation */
if (p_chain->dir < 2 && p_chain->dir >= sbi->num_clusters) { if (!is_valid_cluster(sbi, p_chain->dir)) {
exfat_msg(sb, KERN_ERR, "invalid start cluster (%u)", exfat_err(sb, "invalid start cluster (%u)", p_chain->dir);
p_chain->dir);
return -EIO; return -EIO;
} }
...@@ -305,8 +304,7 @@ int exfat_zeroed_cluster(struct inode *dir, unsigned int clu) ...@@ -305,8 +304,7 @@ int exfat_zeroed_cluster(struct inode *dir, unsigned int clu)
return 0; return 0;
release_bhs: release_bhs:
exfat_msg(sb, KERN_ERR, "failed zeroed sect %llu\n", exfat_err(sb, "failed zeroed sect %llu\n", (unsigned long long)blknr);
(unsigned long long)blknr);
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
bforget(bhs[i]); bforget(bhs[i]);
return err; return err;
...@@ -337,9 +335,8 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, ...@@ -337,9 +335,8 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
/* find new cluster */ /* find new cluster */
if (hint_clu == EXFAT_EOF_CLUSTER) { if (hint_clu == EXFAT_EOF_CLUSTER) {
if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) { if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) {
exfat_msg(sb, KERN_ERR, exfat_err(sb, "sbi->clu_srch_ptr is invalid (%u)\n",
"sbi->clu_srch_ptr is invalid (%u)\n", sbi->clu_srch_ptr);
sbi->clu_srch_ptr);
sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER; sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER;
} }
...@@ -349,8 +346,8 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, ...@@ -349,8 +346,8 @@ int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
} }
/* check cluster validation */ /* check cluster validation */
if (hint_clu < EXFAT_FIRST_CLUSTER && hint_clu >= sbi->num_clusters) { if (!is_valid_cluster(sbi, hint_clu)) {
exfat_msg(sb, KERN_ERR, "hint_cluster is invalid (%u)\n", exfat_err(sb, "hint_cluster is invalid (%u)",
hint_clu); hint_clu);
hint_clu = EXFAT_FIRST_CLUSTER; hint_clu = EXFAT_FIRST_CLUSTER;
if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
......
...@@ -96,11 +96,9 @@ int __exfat_truncate(struct inode *inode, loff_t new_size) ...@@ -96,11 +96,9 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
unsigned int num_clusters_new, num_clusters_phys; unsigned int num_clusters_new, num_clusters_phys;
unsigned int last_clu = EXFAT_FREE_CLUSTER; unsigned int last_clu = EXFAT_FREE_CLUSTER;
struct exfat_chain clu; struct exfat_chain clu;
struct exfat_dentry *ep, *ep2;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_inode_info *ei = EXFAT_I(inode); struct exfat_inode_info *ei = EXFAT_I(inode);
struct exfat_entry_set_cache *es = NULL;
int evict = (ei->dir.dir == DIR_DELETED) ? 1 : 0; int evict = (ei->dir.dir == DIR_DELETED) ? 1 : 0;
/* check if the given file ID is opened */ /* check if the given file ID is opened */
...@@ -153,28 +151,31 @@ int __exfat_truncate(struct inode *inode, loff_t new_size) ...@@ -153,28 +151,31 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
/* update the directory entry */ /* update the directory entry */
if (!evict) { if (!evict) {
struct timespec64 ts; struct timespec64 ts;
struct exfat_dentry *ep, *ep2;
struct exfat_entry_set_cache *es;
es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry,
ES_ALL_ENTRIES, &ep); ES_ALL_ENTRIES);
if (!es) if (!es)
return -EIO; return -EIO;
ep2 = ep + 1; ep = exfat_get_dentry_cached(es, 0);
ep2 = exfat_get_dentry_cached(es, 1);
ts = current_time(inode); ts = current_time(inode);
exfat_set_entry_time(sbi, &ts, exfat_set_entry_time(sbi, &ts,
&ep->dentry.file.modify_tz, &ep->dentry.file.modify_tz,
&ep->dentry.file.modify_time, &ep->dentry.file.modify_time,
&ep->dentry.file.modify_date, &ep->dentry.file.modify_date,
&ep->dentry.file.modify_time_ms); &ep->dentry.file.modify_time_cs);
ep->dentry.file.attr = cpu_to_le16(ei->attr); ep->dentry.file.attr = cpu_to_le16(ei->attr);
/* File size should be zero if there is no cluster allocated */ /* File size should be zero if there is no cluster allocated */
if (ei->start_clu == EXFAT_EOF_CLUSTER) { if (ei->start_clu == EXFAT_EOF_CLUSTER) {
ep->dentry.stream.valid_size = 0; ep2->dentry.stream.valid_size = 0;
ep->dentry.stream.size = 0; ep2->dentry.stream.size = 0;
} else { } else {
ep->dentry.stream.valid_size = cpu_to_le64(new_size); ep2->dentry.stream.valid_size = cpu_to_le64(new_size);
ep->dentry.stream.size = ep->dentry.stream.valid_size; ep2->dentry.stream.size = ep->dentry.stream.valid_size;
} }
if (new_size == 0) { if (new_size == 0) {
...@@ -185,10 +186,8 @@ int __exfat_truncate(struct inode *inode, loff_t new_size) ...@@ -185,10 +186,8 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER; ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER;
} }
if (exfat_update_dir_chksum_with_entry_set(sb, es, exfat_update_dir_chksum_with_entry_set(es);
inode_needs_sync(inode))) exfat_free_dentry_set(es, inode_needs_sync(inode));
return -EIO;
kfree(es);
} }
/* cut off from the FAT chain */ /* cut off from the FAT chain */
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
static int __exfat_write_inode(struct inode *inode, int sync) static int __exfat_write_inode(struct inode *inode, int sync)
{ {
int ret = -EIO;
unsigned long long on_disk_size; unsigned long long on_disk_size;
struct exfat_dentry *ep, *ep2; struct exfat_dentry *ep, *ep2;
struct exfat_entry_set_cache *es = NULL; struct exfat_entry_set_cache *es = NULL;
...@@ -43,11 +42,11 @@ static int __exfat_write_inode(struct inode *inode, int sync) ...@@ -43,11 +42,11 @@ static int __exfat_write_inode(struct inode *inode, int sync)
exfat_set_vol_flags(sb, VOL_DIRTY); exfat_set_vol_flags(sb, VOL_DIRTY);
/* get the directory entry of given file or directory */ /* get the directory entry of given file or directory */
es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES, es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES);
&ep);
if (!es) if (!es)
return -EIO; return -EIO;
ep2 = ep + 1; ep = exfat_get_dentry_cached(es, 0);
ep2 = exfat_get_dentry_cached(es, 1);
ep->dentry.file.attr = cpu_to_le16(exfat_make_attr(inode)); ep->dentry.file.attr = cpu_to_le16(exfat_make_attr(inode));
...@@ -56,12 +55,12 @@ static int __exfat_write_inode(struct inode *inode, int sync) ...@@ -56,12 +55,12 @@ static int __exfat_write_inode(struct inode *inode, int sync)
&ep->dentry.file.create_tz, &ep->dentry.file.create_tz,
&ep->dentry.file.create_time, &ep->dentry.file.create_time,
&ep->dentry.file.create_date, &ep->dentry.file.create_date,
&ep->dentry.file.create_time_ms); &ep->dentry.file.create_time_cs);
exfat_set_entry_time(sbi, &inode->i_mtime, exfat_set_entry_time(sbi, &inode->i_mtime,
&ep->dentry.file.modify_tz, &ep->dentry.file.modify_tz,
&ep->dentry.file.modify_time, &ep->dentry.file.modify_time,
&ep->dentry.file.modify_date, &ep->dentry.file.modify_date,
&ep->dentry.file.modify_time_ms); &ep->dentry.file.modify_time_cs);
exfat_set_entry_time(sbi, &inode->i_atime, exfat_set_entry_time(sbi, &inode->i_atime,
&ep->dentry.file.access_tz, &ep->dentry.file.access_tz,
&ep->dentry.file.access_time, &ep->dentry.file.access_time,
...@@ -77,9 +76,9 @@ static int __exfat_write_inode(struct inode *inode, int sync) ...@@ -77,9 +76,9 @@ static int __exfat_write_inode(struct inode *inode, int sync)
ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size); ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size);
ep2->dentry.stream.size = ep2->dentry.stream.valid_size; ep2->dentry.stream.size = ep2->dentry.stream.valid_size;
ret = exfat_update_dir_chksum_with_entry_set(sb, es, sync); exfat_update_dir_chksum_with_entry_set(es);
kfree(es); exfat_free_dentry_set(es, sync);
return ret; return 0;
} }
int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) int exfat_write_inode(struct inode *inode, struct writeback_control *wbc)
...@@ -110,8 +109,6 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, ...@@ -110,8 +109,6 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
int ret, modified = false; int ret, modified = false;
unsigned int last_clu; unsigned int last_clu;
struct exfat_chain new_clu; struct exfat_chain new_clu;
struct exfat_dentry *ep;
struct exfat_entry_set_cache *es = NULL;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_inode_info *ei = EXFAT_I(inode); struct exfat_inode_info *ei = EXFAT_I(inode);
...@@ -222,34 +219,28 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset, ...@@ -222,34 +219,28 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
num_clusters += num_to_be_allocated; num_clusters += num_to_be_allocated;
*clu = new_clu.dir; *clu = new_clu.dir;
if (ei->dir.dir != DIR_DELETED) { if (ei->dir.dir != DIR_DELETED && modified) {
struct exfat_dentry *ep;
struct exfat_entry_set_cache *es;
es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry,
ES_ALL_ENTRIES, &ep); ES_ALL_ENTRIES);
if (!es) if (!es)
return -EIO; return -EIO;
/* get stream entry */ /* get stream entry */
ep++; ep = exfat_get_dentry_cached(es, 1);
/* update directory entry */ /* update directory entry */
if (modified) { ep->dentry.stream.flags = ei->flags;
if (ep->dentry.stream.flags != ei->flags) ep->dentry.stream.start_clu =
ep->dentry.stream.flags = ei->flags; cpu_to_le32(ei->start_clu);
ep->dentry.stream.valid_size =
if (le32_to_cpu(ep->dentry.stream.start_clu) != cpu_to_le64(i_size_read(inode));
ei->start_clu) ep->dentry.stream.size =
ep->dentry.stream.start_clu = ep->dentry.stream.valid_size;
cpu_to_le32(ei->start_clu);
exfat_update_dir_chksum_with_entry_set(es);
ep->dentry.stream.valid_size = exfat_free_dentry_set(es, inode_needs_sync(inode));
cpu_to_le64(i_size_read(inode));
ep->dentry.stream.size =
ep->dentry.stream.valid_size;
}
if (exfat_update_dir_chksum_with_entry_set(sb, es,
inode_needs_sync(inode)))
return -EIO;
kfree(es);
} /* end of if != DIR_DELETED */ } /* end of if != DIR_DELETED */
......
...@@ -32,7 +32,7 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) ...@@ -32,7 +32,7 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
va_start(args, fmt); va_start(args, fmt);
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
exfat_msg(sb, KERN_ERR, "error, %pV\n", &vaf); exfat_err(sb, "error, %pV", &vaf);
va_end(args); va_end(args);
} }
...@@ -41,7 +41,7 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) ...@@ -41,7 +41,7 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
sb->s_id); sb->s_id);
} else if (opts->errors == EXFAT_ERRORS_RO && !sb_rdonly(sb)) { } else if (opts->errors == EXFAT_ERRORS_RO && !sb_rdonly(sb)) {
sb->s_flags |= SB_RDONLY; sb->s_flags |= SB_RDONLY;
exfat_msg(sb, KERN_ERR, "Filesystem has been set read-only"); exfat_err(sb, "Filesystem has been set read-only");
} }
} }
...@@ -75,7 +75,7 @@ static void exfat_adjust_tz(struct timespec64 *ts, u8 tz_off) ...@@ -75,7 +75,7 @@ static void exfat_adjust_tz(struct timespec64 *ts, u8 tz_off)
/* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */ /* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 tz, __le16 time, __le16 date, u8 time_ms) u8 tz, __le16 time, __le16 date, u8 time_cs)
{ {
u16 t = le16_to_cpu(time); u16 t = le16_to_cpu(time);
u16 d = le16_to_cpu(date); u16 d = le16_to_cpu(date);
...@@ -84,10 +84,10 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, ...@@ -84,10 +84,10 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
t >> 11, (t >> 5) & 0x003F, (t & 0x001F) << 1); t >> 11, (t >> 5) & 0x003F, (t & 0x001F) << 1);
/* time_ms field represent 0 ~ 199(1990 ms) */ /* time_cs field represent 0 ~ 199cs(1990 ms) */
if (time_ms) { if (time_cs) {
ts->tv_sec += time_ms / 100; ts->tv_sec += time_cs / 100;
ts->tv_nsec = (time_ms % 100) * 10 * NSEC_PER_MSEC; ts->tv_nsec = (time_cs % 100) * 10 * NSEC_PER_MSEC;
} else } else
ts->tv_nsec = 0; ts->tv_nsec = 0;
...@@ -101,7 +101,7 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, ...@@ -101,7 +101,7 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
/* Convert linear UNIX date to a EXFAT time/date pair. */ /* Convert linear UNIX date to a EXFAT time/date pair. */
void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 *tz, __le16 *time, __le16 *date, u8 *time_ms) u8 *tz, __le16 *time, __le16 *date, u8 *time_cs)
{ {
struct tm tm; struct tm tm;
u16 t, d; u16 t, d;
...@@ -113,9 +113,9 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts, ...@@ -113,9 +113,9 @@ void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
*time = cpu_to_le16(t); *time = cpu_to_le16(t);
*date = cpu_to_le16(d); *date = cpu_to_le16(d);
/* time_ms field represent 0 ~ 199(1990 ms) */ /* time_cs field represent 0 ~ 199cs(1990 ms) */
if (time_ms) if (time_cs)
*time_ms = (tm.tm_sec & 1) * 100 + *time_cs = (tm.tm_sec & 1) * 100 +
ts->tv_nsec / (10 * NSEC_PER_MSEC); ts->tv_nsec / (10 * NSEC_PER_MSEC);
/* /*
...@@ -136,17 +136,29 @@ void exfat_truncate_atime(struct timespec64 *ts) ...@@ -136,17 +136,29 @@ void exfat_truncate_atime(struct timespec64 *ts)
ts->tv_nsec = 0; ts->tv_nsec = 0;
} }
unsigned short exfat_calc_chksum_2byte(void *data, int len, u16 exfat_calc_chksum16(void *data, int len, u16 chksum, int type)
unsigned short chksum, int type)
{ {
int i; int i;
unsigned char *c = (unsigned char *)data; u8 *c = (u8 *)data;
for (i = 0; i < len; i++, c++) { for (i = 0; i < len; i++, c++) {
if (((i == 2) || (i == 3)) && (type == CS_DIR_ENTRY)) if (unlikely(type == CS_DIR_ENTRY && (i == 2 || i == 3)))
continue; continue;
chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + chksum = ((chksum << 15) | (chksum >> 1)) + *c;
(unsigned short)*c; }
return chksum;
}
u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type)
{
int i;
u8 *c = (u8 *)data;
for (i = 0; i < len; i++, c++) {
if (unlikely(type == CS_BOOT_SECTOR &&
(i == 106 || i == 107 || i == 112)))
continue;
chksum = ((chksum << 31) | (chksum >> 1)) + *c;
} }
return chksum; return chksum;
} }
......
...@@ -147,16 +147,10 @@ static int exfat_utf8_d_hash(const struct dentry *dentry, struct qstr *qstr) ...@@ -147,16 +147,10 @@ static int exfat_utf8_d_hash(const struct dentry *dentry, struct qstr *qstr)
return charlen; return charlen;
/* /*
* Convert to UTF-16: code points above U+FFFF are encoded as
* surrogate pairs.
* exfat_toupper() works only for code points up to the U+FFFF. * exfat_toupper() works only for code points up to the U+FFFF.
*/ */
if (u > 0xFFFF) { hash = partial_name_hash(u <= 0xFFFF ? exfat_toupper(sb, u) : u,
hash = partial_name_hash(exfat_high_surrogate(u), hash); hash);
hash = partial_name_hash(exfat_low_surrogate(u), hash);
} else {
hash = partial_name_hash(exfat_toupper(sb, u), hash);
}
} }
qstr->hash = end_name_hash(hash); qstr->hash = end_name_hash(hash);
...@@ -185,14 +179,9 @@ static int exfat_utf8_d_cmp(const struct dentry *dentry, unsigned int len, ...@@ -185,14 +179,9 @@ static int exfat_utf8_d_cmp(const struct dentry *dentry, unsigned int len,
if (u_a <= 0xFFFF && u_b <= 0xFFFF) { if (u_a <= 0xFFFF && u_b <= 0xFFFF) {
if (exfat_toupper(sb, u_a) != exfat_toupper(sb, u_b)) if (exfat_toupper(sb, u_a) != exfat_toupper(sb, u_b))
return 1; return 1;
} else if (u_a > 0xFFFF && u_b > 0xFFFF) {
if (exfat_low_surrogate(u_a) !=
exfat_low_surrogate(u_b) ||
exfat_high_surrogate(u_a) !=
exfat_high_surrogate(u_b))
return 1;
} else { } else {
return 1; if (u_a != u_b)
return 1;
} }
} }
...@@ -611,8 +600,6 @@ static int exfat_find(struct inode *dir, struct qstr *qname, ...@@ -611,8 +600,6 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
int ret, dentry, num_entries, count; int ret, dentry, num_entries, count;
struct exfat_chain cdir; struct exfat_chain cdir;
struct exfat_uni_name uni_name; struct exfat_uni_name uni_name;
struct exfat_dentry *ep, *ep2;
struct exfat_entry_set_cache *es = NULL;
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_inode_info *ei = EXFAT_I(dir); struct exfat_inode_info *ei = EXFAT_I(dir);
...@@ -671,10 +658,14 @@ static int exfat_find(struct inode *dir, struct qstr *qname, ...@@ -671,10 +658,14 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
info->num_subdirs = count; info->num_subdirs = count;
} else { } else {
es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES, &ep); struct exfat_dentry *ep, *ep2;
struct exfat_entry_set_cache *es;
es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES);
if (!es) if (!es)
return -EIO; return -EIO;
ep2 = ep + 1; ep = exfat_get_dentry_cached(es, 0);
ep2 = exfat_get_dentry_cached(es, 1);
info->type = exfat_get_entry_type(ep); info->type = exfat_get_entry_type(ep);
info->attr = le16_to_cpu(ep->dentry.file.attr); info->attr = le16_to_cpu(ep->dentry.file.attr);
...@@ -692,7 +683,7 @@ static int exfat_find(struct inode *dir, struct qstr *qname, ...@@ -692,7 +683,7 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
exfat_fs_error(sb, exfat_fs_error(sb,
"non-zero size file starts with zero cluster (size : %llu, p_dir : %u, entry : 0x%08x)", "non-zero size file starts with zero cluster (size : %llu, p_dir : %u, entry : 0x%08x)",
i_size_read(dir), ei->dir.dir, ei->entry); i_size_read(dir), ei->dir.dir, ei->entry);
kfree(es); exfat_free_dentry_set(es, false);
return -EIO; return -EIO;
} }
...@@ -700,18 +691,18 @@ static int exfat_find(struct inode *dir, struct qstr *qname, ...@@ -700,18 +691,18 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
ep->dentry.file.create_tz, ep->dentry.file.create_tz,
ep->dentry.file.create_time, ep->dentry.file.create_time,
ep->dentry.file.create_date, ep->dentry.file.create_date,
ep->dentry.file.create_time_ms); ep->dentry.file.create_time_cs);
exfat_get_entry_time(sbi, &info->mtime, exfat_get_entry_time(sbi, &info->mtime,
ep->dentry.file.modify_tz, ep->dentry.file.modify_tz,
ep->dentry.file.modify_time, ep->dentry.file.modify_time,
ep->dentry.file.modify_date, ep->dentry.file.modify_date,
ep->dentry.file.modify_time_ms); ep->dentry.file.modify_time_cs);
exfat_get_entry_time(sbi, &info->atime, exfat_get_entry_time(sbi, &info->atime,
ep->dentry.file.access_tz, ep->dentry.file.access_tz,
ep->dentry.file.access_time, ep->dentry.file.access_time,
ep->dentry.file.access_date, ep->dentry.file.access_date,
0); 0);
kfree(es); exfat_free_dentry_set(es, false);
if (info->type == TYPE_DIR) { if (info->type == TYPE_DIR) {
exfat_chain_set(&cdir, info->start_clu, exfat_chain_set(&cdir, info->start_clu,
...@@ -778,8 +769,8 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, ...@@ -778,8 +769,8 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry,
if (d_unhashed(alias)) { if (d_unhashed(alias)) {
WARN_ON(alias->d_name.hash_len != WARN_ON(alias->d_name.hash_len !=
dentry->d_name.hash_len); dentry->d_name.hash_len);
exfat_msg(sb, KERN_INFO, exfat_info(sb, "rehashed a dentry(%p) in read lookup",
"rehashed a dentry(%p) in read lookup", alias); alias);
d_drop(dentry); d_drop(dentry);
d_rehash(alias); d_rehash(alias);
} else if (!S_ISDIR(i_mode)) { } else if (!S_ISDIR(i_mode)) {
...@@ -824,7 +815,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) ...@@ -824,7 +815,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
exfat_chain_dup(&cdir, &ei->dir); exfat_chain_dup(&cdir, &ei->dir);
entry = ei->entry; entry = ei->entry;
if (ei->dir.dir == DIR_DELETED) { if (ei->dir.dir == DIR_DELETED) {
exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry"); exfat_err(sb, "abnormal access to deleted dentry");
err = -ENOENT; err = -ENOENT;
goto unlock; goto unlock;
} }
...@@ -979,7 +970,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -979,7 +970,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
entry = ei->entry; entry = ei->entry;
if (ei->dir.dir == DIR_DELETED) { if (ei->dir.dir == DIR_DELETED) {
exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry"); exfat_err(sb, "abnormal access to deleted dentry");
err = -ENOENT; err = -ENOENT;
goto unlock; goto unlock;
} }
...@@ -991,9 +982,8 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -991,9 +982,8 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
err = exfat_check_dir_empty(sb, &clu_to_free); err = exfat_check_dir_empty(sb, &clu_to_free);
if (err) { if (err) {
if (err == -EIO) if (err == -EIO)
exfat_msg(sb, KERN_ERR, exfat_err(sb, "failed to exfat_check_dir_empty : err(%d)",
"failed to exfat_check_dir_empty : err(%d)", err);
err);
goto unlock; goto unlock;
} }
...@@ -1014,9 +1004,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -1014,9 +1004,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
err = exfat_remove_entries(dir, &cdir, entry, 0, num_entries); err = exfat_remove_entries(dir, &cdir, entry, 0, num_entries);
if (err) { if (err) {
exfat_msg(sb, KERN_ERR, exfat_err(sb, "failed to exfat_remove_entries : err(%d)", err);
"failed to exfat_remove_entries : err(%d)",
err);
goto unlock; goto unlock;
} }
ei->dir.dir = DIR_DELETED; ei->dir.dir = DIR_DELETED;
...@@ -1245,8 +1233,7 @@ static int __exfat_rename(struct inode *old_parent_inode, ...@@ -1245,8 +1233,7 @@ static int __exfat_rename(struct inode *old_parent_inode,
return -EINVAL; return -EINVAL;
if (ei->dir.dir == DIR_DELETED) { if (ei->dir.dir == DIR_DELETED) {
exfat_msg(sb, KERN_ERR, exfat_err(sb, "abnormal access to deleted source dentry");
"abnormal access to deleted source dentry");
return -ENOENT; return -ENOENT;
} }
...@@ -1268,8 +1255,7 @@ static int __exfat_rename(struct inode *old_parent_inode, ...@@ -1268,8 +1255,7 @@ static int __exfat_rename(struct inode *old_parent_inode,
new_ei = EXFAT_I(new_inode); new_ei = EXFAT_I(new_inode);
if (new_ei->dir.dir == DIR_DELETED) { if (new_ei->dir.dir == DIR_DELETED) {
exfat_msg(sb, KERN_ERR, exfat_err(sb, "abnormal access to deleted target dentry");
"abnormal access to deleted target dentry");
goto out; goto out;
} }
...@@ -1431,8 +1417,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1431,8 +1417,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
if (S_ISDIR(new_inode->i_mode)) if (S_ISDIR(new_inode->i_mode))
drop_nlink(new_inode); drop_nlink(new_inode);
} else { } else {
exfat_msg(sb, KERN_WARNING, exfat_warn(sb, "abnormal access to an inode dropped");
"abnormal access to an inode dropped");
WARN_ON(new_inode->i_nlink == 0); WARN_ON(new_inode->i_nlink == 0);
} }
new_inode->i_ctime = EXFAT_I(new_inode)->i_crtime = new_inode->i_ctime = EXFAT_I(new_inode)->i_crtime =
......
...@@ -503,21 +503,17 @@ static int exfat_utf8_to_utf16(struct super_block *sb, ...@@ -503,21 +503,17 @@ static int exfat_utf8_to_utf16(struct super_block *sb,
unilen = utf8s_to_utf16s(p_cstring, len, UTF16_HOST_ENDIAN, unilen = utf8s_to_utf16s(p_cstring, len, UTF16_HOST_ENDIAN,
(wchar_t *)uniname, MAX_NAME_LENGTH + 2); (wchar_t *)uniname, MAX_NAME_LENGTH + 2);
if (unilen < 0) { if (unilen < 0) {
exfat_msg(sb, KERN_ERR, exfat_err(sb, "failed to %s (err : %d) nls len : %d",
"failed to %s (err : %d) nls len : %d", __func__, unilen, len);
__func__, unilen, len);
return unilen; return unilen;
} }
if (unilen > MAX_NAME_LENGTH) { if (unilen > MAX_NAME_LENGTH) {
exfat_msg(sb, KERN_ERR, exfat_err(sb, "failed to %s (estr:ENAMETOOLONG) nls len : %d, unilen : %d > %d",
"failed to %s (estr:ENAMETOOLONG) nls len : %d, unilen : %d > %d", __func__, len, unilen, MAX_NAME_LENGTH);
__func__, len, unilen, MAX_NAME_LENGTH);
return -ENAMETOOLONG; return -ENAMETOOLONG;
} }
p_uniname->name_len = unilen & 0xFF;
for (i = 0; i < unilen; i++) { for (i = 0; i < unilen; i++) {
if (*uniname < 0x0020 || if (*uniname < 0x0020 ||
exfat_wstrchr(bad_uni_chars, *uniname)) exfat_wstrchr(bad_uni_chars, *uniname))
...@@ -529,7 +525,7 @@ static int exfat_utf8_to_utf16(struct super_block *sb, ...@@ -529,7 +525,7 @@ static int exfat_utf8_to_utf16(struct super_block *sb,
*uniname = '\0'; *uniname = '\0';
p_uniname->name_len = unilen; p_uniname->name_len = unilen;
p_uniname->name_hash = exfat_calc_chksum_2byte(upname, unilen << 1, 0, p_uniname->name_hash = exfat_calc_chksum16(upname, unilen << 1, 0,
CS_DEFAULT); CS_DEFAULT);
if (p_lossy) if (p_lossy)
...@@ -537,22 +533,9 @@ static int exfat_utf8_to_utf16(struct super_block *sb, ...@@ -537,22 +533,9 @@ static int exfat_utf8_to_utf16(struct super_block *sb,
return unilen; return unilen;
} }
#define PLANE_SIZE 0x00010000
#define SURROGATE_MASK 0xfffff800 #define SURROGATE_MASK 0xfffff800
#define SURROGATE_PAIR 0x0000d800 #define SURROGATE_PAIR 0x0000d800
#define SURROGATE_LOW 0x00000400 #define SURROGATE_LOW 0x00000400
#define SURROGATE_BITS 0x000003ff
unsigned short exfat_high_surrogate(unicode_t u)
{
return ((u - PLANE_SIZE) >> 10) + SURROGATE_PAIR;
}
unsigned short exfat_low_surrogate(unicode_t u)
{
return ((u - PLANE_SIZE) & SURROGATE_BITS) | SURROGATE_PAIR |
SURROGATE_LOW;
}
static int __exfat_utf16_to_nls(struct super_block *sb, static int __exfat_utf16_to_nls(struct super_block *sb,
struct exfat_uni_name *p_uniname, unsigned char *p_cstring, struct exfat_uni_name *p_uniname, unsigned char *p_cstring,
...@@ -638,7 +621,7 @@ static int exfat_nls_to_ucs2(struct super_block *sb, ...@@ -638,7 +621,7 @@ static int exfat_nls_to_ucs2(struct super_block *sb,
*uniname = '\0'; *uniname = '\0';
p_uniname->name_len = unilen; p_uniname->name_len = unilen;
p_uniname->name_hash = exfat_calc_chksum_2byte(upname, unilen << 1, 0, p_uniname->name_hash = exfat_calc_chksum16(upname, unilen << 1, 0,
CS_DEFAULT); CS_DEFAULT);
if (p_lossy) if (p_lossy)
...@@ -670,7 +653,8 @@ static int exfat_load_upcase_table(struct super_block *sb, ...@@ -670,7 +653,8 @@ static int exfat_load_upcase_table(struct super_block *sb,
{ {
struct exfat_sb_info *sbi = EXFAT_SB(sb); struct exfat_sb_info *sbi = EXFAT_SB(sb);
unsigned int sect_size = sb->s_blocksize; unsigned int sect_size = sb->s_blocksize;
unsigned int i, index = 0, checksum = 0; unsigned int i, index = 0;
u32 chksum = 0;
int ret; int ret;
unsigned char skip = false; unsigned char skip = false;
unsigned short *upcase_table; unsigned short *upcase_table;
...@@ -687,9 +671,8 @@ static int exfat_load_upcase_table(struct super_block *sb, ...@@ -687,9 +671,8 @@ static int exfat_load_upcase_table(struct super_block *sb,
bh = sb_bread(sb, sector); bh = sb_bread(sb, sector);
if (!bh) { if (!bh) {
exfat_msg(sb, KERN_ERR, exfat_err(sb, "failed to read sector(0x%llx)\n",
"failed to read sector(0x%llx)\n", (unsigned long long)sector);
(unsigned long long)sector);
ret = -EIO; ret = -EIO;
goto free_table; goto free_table;
} }
...@@ -697,13 +680,6 @@ static int exfat_load_upcase_table(struct super_block *sb, ...@@ -697,13 +680,6 @@ static int exfat_load_upcase_table(struct super_block *sb,
for (i = 0; i < sect_size && index <= 0xFFFF; i += 2) { for (i = 0; i < sect_size && index <= 0xFFFF; i += 2) {
unsigned short uni = get_unaligned_le16(bh->b_data + i); unsigned short uni = get_unaligned_le16(bh->b_data + i);
checksum = ((checksum & 1) ? 0x80000000 : 0) +
(checksum >> 1) +
*(((unsigned char *)bh->b_data) + i);
checksum = ((checksum & 1) ? 0x80000000 : 0) +
(checksum >> 1) +
*(((unsigned char *)bh->b_data) + (i + 1));
if (skip) { if (skip) {
index += uni; index += uni;
skip = false; skip = false;
...@@ -716,15 +692,15 @@ static int exfat_load_upcase_table(struct super_block *sb, ...@@ -716,15 +692,15 @@ static int exfat_load_upcase_table(struct super_block *sb,
index++; index++;
} }
} }
chksum = exfat_calc_chksum32(bh->b_data, i, chksum, CS_DEFAULT);
brelse(bh); brelse(bh);
} }
if (index >= 0xFFFF && utbl_checksum == checksum) if (index >= 0xFFFF && utbl_checksum == chksum)
return 0; return 0;
exfat_msg(sb, KERN_ERR, exfat_err(sb, "failed to load upcase table (idx : 0x%08x, chksum : 0x%08x, utbl_chksum : 0x%08x)",
"failed to load upcase table (idx : 0x%08x, chksum : 0x%08x, utbl_chksum : 0x%08x)\n", index, chksum, utbl_checksum);
index, checksum, utbl_checksum);
ret = -EINVAL; ret = -EINVAL;
free_table: free_table:
exfat_free_upcase_table(sbi); exfat_free_upcase_table(sbi);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment