Commit ad57a102 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ config EXFAT_DEFAULT_IOCHARSET
	depends on EXFAT_FS
	help
	  Set this to the default input/output character set to use for
	  converting between the encoding is used for user visible filename and
	  UTF-16 character that exfat filesystem use, and can be overridden with
	  the "iocharset" mount option for exFAT filesystems.
	  converting between the encoding that is used for user visible
	  filenames and the UTF-16 character encoding that the exFAT
	  filesystem uses.  This can be overridden with the "iocharset" mount
	  option for the exFAT filesystems.
+3 −5
Original line number Diff line number Diff line
@@ -58,8 +58,7 @@ static int exfat_allocate_bitmap(struct super_block *sb,
	need_map_size = ((EXFAT_DATA_CLUSTER_COUNT(sbi) - 1) / BITS_PER_BYTE)
		+ 1;
	if (need_map_size != map_size) {
		exfat_msg(sb, KERN_ERR,
				"bogus allocation bitmap size(need : %u, cur : %lld)",
		exfat_err(sb, "bogus allocation bitmap size(need : %u, cur : %lld)",
			  need_map_size, map_size);
		/*
		 * Only allowed when bogus allocation
@@ -192,8 +191,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
			(1 << sbi->sect_per_clus_bits), GFP_NOFS, 0);

		if (ret_discard == -EOPNOTSUPP) {
			exfat_msg(sb, KERN_ERR,
				"discard not supported by device, disabling");
			exfat_err(sb, "discard not supported by device, disabling");
			opts->discard = 0;
		}
	}
+87 −135
Original line number Diff line number Diff line
@@ -32,35 +32,30 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb,
		struct exfat_chain *p_dir, int entry, unsigned short *uniname)
{
	int i;
	struct exfat_dentry *ep;
	struct exfat_entry_set_cache *es;

	es = exfat_get_dentry_set(sb, p_dir, entry, ES_ALL_ENTRIES, &ep);
	es = exfat_get_dentry_set(sb, p_dir, entry, ES_ALL_ENTRIES);
	if (!es)
		return;

	if (es->num_entries < 3)
		goto free_es;

	ep += 2;

	/*
	 * First entry  : file entry
	 * Second entry : stream-extension entry
	 * Third entry  : first file-name entry
	 * So, the index of first file-name dentry should start from 2.
	 */
	for (i = 2; i < es->num_entries; i++, ep++) {
	for (i = 2; i < es->num_entries; i++) {
		struct exfat_dentry *ep = exfat_get_dentry_cached(es, i);

		/* end of name entry */
		if (exfat_get_entry_type(ep) != TYPE_EXTEND)
			goto free_es;
			break;

		exfat_extract_uni_name(ep, uniname);
		uniname += EXFAT_FILE_NAME_LEN;
	}

free_es:
	kfree(es);
	exfat_free_dentry_set(es, false);
}

/* read a directory entry from the opened directory */
@@ -137,12 +132,12 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry)
					ep->dentry.file.create_tz,
					ep->dentry.file.create_time,
					ep->dentry.file.create_date,
					ep->dentry.file.create_time_ms);
					ep->dentry.file.create_time_cs);
			exfat_get_entry_time(sbi, &dir_entry->mtime,
					ep->dentry.file.modify_tz,
					ep->dentry.file.modify_time,
					ep->dentry.file.modify_date,
					ep->dentry.file.modify_time_ms);
					ep->dentry.file.modify_time_cs);
			exfat_get_entry_time(sbi, &dir_entry->atime,
					ep->dentry.file.access_tz,
					ep->dentry.file.access_time,
@@ -461,12 +456,12 @@ int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir,
			&ep->dentry.file.create_tz,
			&ep->dentry.file.create_time,
			&ep->dentry.file.create_date,
			&ep->dentry.file.create_time_ms);
			&ep->dentry.file.create_time_cs);
	exfat_set_entry_time(sbi, &ts,
			&ep->dentry.file.modify_tz,
			&ep->dentry.file.modify_time,
			&ep->dentry.file.modify_date,
			&ep->dentry.file.modify_time_ms);
			&ep->dentry.file.modify_time_cs);
	exfat_set_entry_time(sbi, &ts,
			&ep->dentry.file.access_tz,
			&ep->dentry.file.access_time,
@@ -496,7 +491,7 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
	int ret = 0;
	int i, num_entries;
	sector_t sector;
	unsigned short chksum;
	u16 chksum;
	struct exfat_dentry *ep, *fep;
	struct buffer_head *fbh, *bh;

@@ -505,7 +500,7 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
		return -EIO;

	num_entries = fep->dentry.file.num_ext + 1;
	chksum = exfat_calc_chksum_2byte(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY);
	chksum = exfat_calc_chksum16(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY);

	for (i = 1; i < num_entries; i++) {
		ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, NULL);
@@ -513,7 +508,7 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
			ret = -EIO;
			goto release_fbh;
		}
		chksum = exfat_calc_chksum_2byte(ep, DENTRY_SIZE, chksum,
		chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, chksum,
				CS_DEFAULT);
		brelse(bh);
	}
@@ -590,62 +585,33 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir,
	return 0;
}

int exfat_update_dir_chksum_with_entry_set(struct super_block *sb,
		struct exfat_entry_set_cache *es, int sync)
void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es)
{
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	struct buffer_head *bh;
	sector_t sec = es->sector;
	unsigned int off = es->offset;
	int chksum_type = CS_DIR_ENTRY, i, num_entries = es->num_entries;
	unsigned int buf_off = (off - es->offset);
	unsigned int remaining_byte_in_sector, copy_entries, clu;
	int chksum_type = CS_DIR_ENTRY, i;
	unsigned short chksum = 0;
	struct exfat_dentry *ep;

	for (i = 0; i < num_entries; i++) {
		chksum = exfat_calc_chksum_2byte(&es->entries[i], DENTRY_SIZE,
			chksum, chksum_type);
	for (i = 0; i < es->num_entries; i++) {
		ep = exfat_get_dentry_cached(es, i);
		chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, chksum,
					     chksum_type);
		chksum_type = CS_DEFAULT;
	}
	ep = exfat_get_dentry_cached(es, 0);
	ep->dentry.file.checksum = cpu_to_le16(chksum);
	es->modified = true;
}

	es->entries[0].dentry.file.checksum = cpu_to_le16(chksum);

	while (num_entries) {
		/* write per sector base */
		remaining_byte_in_sector = (1 << sb->s_blocksize_bits) - off;
		copy_entries = min_t(int,
			EXFAT_B_TO_DEN(remaining_byte_in_sector),
			num_entries);
		bh = sb_bread(sb, sec);
		if (!bh)
			goto err_out;
		memcpy(bh->b_data + off,
			(unsigned char *)&es->entries[0] + buf_off,
			EXFAT_DEN_TO_B(copy_entries));
		exfat_update_bh(sb, bh, sync);
		brelse(bh);
		num_entries -= copy_entries;
void exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync)
{
	int i;

		if (num_entries) {
			/* get next sector */
			if (exfat_is_last_sector_in_cluster(sbi, sec)) {
				clu = exfat_sector_to_cluster(sbi, sec);
				if (es->alloc_flag == ALLOC_NO_FAT_CHAIN)
					clu++;
				else if (exfat_get_next_cluster(sb, &clu))
					goto err_out;
				sec = exfat_cluster_to_sector(sbi, clu);
			} else {
				sec++;
	for (i = 0; i < es->num_bh; i++) {
		if (es->modified)
			exfat_update_bh(es->sb, es->bh[i], sync);
		brelse(es->bh[i]);
	}
			off = 0;
			buf_off += EXFAT_DEN_TO_B(copy_entries);
		}
	}

	return 0;
err_out:
	return -EIO;
	kfree(es);
}

static int exfat_walk_fat_chain(struct super_block *sb,
@@ -720,8 +686,7 @@ static int exfat_dir_readahead(struct super_block *sb, sector_t sec)
		return 0;

	if (sec < sbi->data_start_sector) {
		exfat_msg(sb, KERN_ERR,
			"requested sector is invalid(sect:%llu, root:%llu)",
		exfat_err(sb, "requested sector is invalid(sect:%llu, root:%llu)",
			  (unsigned long long)sec, sbi->data_start_sector);
		return -EIO;
	}
@@ -750,7 +715,7 @@ struct exfat_dentry *exfat_get_dentry(struct super_block *sb,
	sector_t sec;

	if (p_dir->dir == DIR_DELETED) {
		exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry\n");
		exfat_err(sb, "abnormal access to deleted dentry");
		return NULL;
	}

@@ -821,39 +786,45 @@ static bool exfat_validate_entry(unsigned int type,
	}
}

struct exfat_dentry *exfat_get_dentry_cached(
	struct exfat_entry_set_cache *es, int num)
{
	int off = es->start_off + num * DENTRY_SIZE;
	struct buffer_head *bh = es->bh[EXFAT_B_TO_BLK(off, es->sb)];
	char *p = bh->b_data + EXFAT_BLK_OFFSET(off, es->sb);

	return (struct exfat_dentry *)p;
}

/*
 * Returns a set of dentries for a file or dir.
 *
 * Note that this is a copy (dump) of dentries so that user should
 * call write_entry_set() to apply changes made in this entry set
 * to the real device.
 * Note It provides a direct pointer to bh->data via exfat_get_dentry_cached().
 * User should call exfat_get_dentry_set() after setting 'modified' to apply
 * changes made in this entry set to the real device.
 *
 * in:
 *   sb+p_dir+entry: indicates a file/dir
 *   type:  specifies how many dentries should be included.
 * out:
 *   file_ep: will point the first dentry(= file dentry) on success
 * return:
 *   pointer of entry set on success,
 *   NULL on failure.
 */
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_dentry **file_ep)
		struct exfat_chain *p_dir, int entry, unsigned int type)
{
	int ret;
	int ret, i, num_bh;
	unsigned int off, byte_offset, clu = 0;
	unsigned int entry_type;
	sector_t sec;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	struct exfat_entry_set_cache *es;
	struct exfat_dentry *ep, *pos;
	unsigned char num_entries;
	struct exfat_dentry *ep;
	int num_entries;
	enum exfat_validate_dentry_mode mode = ES_MODE_STARTED;
	struct buffer_head *bh;

	if (p_dir->dir == DIR_DELETED) {
		exfat_msg(sb, KERN_ERR, "access to deleted dentry\n");
		exfat_err(sb, "access to deleted dentry");
		return NULL;
	}

@@ -862,11 +833,18 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,
	if (ret)
		return NULL;

	es = kzalloc(sizeof(*es), GFP_KERNEL);
	if (!es)
		return NULL;
	es->sb = sb;
	es->modified = false;

	/* byte offset in cluster */
	byte_offset = EXFAT_CLU_OFFSET(byte_offset, sbi);

	/* byte offset in sector */
	off = EXFAT_BLK_OFFSET(byte_offset, sb);
	es->start_off = off;

	/* sector offset in cluster */
	sec = EXFAT_B_TO_BLK(byte_offset, sb);
@@ -874,42 +852,22 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,

	bh = sb_bread(sb, sec);
	if (!bh)
		return NULL;

	ep = (struct exfat_dentry *)(bh->b_data + off);
	entry_type = exfat_get_entry_type(ep);
		goto free_es;
	es->bh[es->num_bh++] = bh;

	if (entry_type != TYPE_FILE && entry_type != TYPE_DIR)
		goto release_bh;
	ep = exfat_get_dentry_cached(es, 0);
	if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode))
		goto free_es;

	num_entries = type == ES_ALL_ENTRIES ?
		ep->dentry.file.num_ext + 1 : type;
	es = kmalloc(struct_size(es, entries, num_entries), GFP_KERNEL);
	if (!es)
		goto release_bh;

	es->num_entries = num_entries;
	es->sector = sec;
	es->offset = off;
	es->alloc_flag = p_dir->flags;

	pos = &es->entries[0];

	while (num_entries) {
		if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode))
			goto free_es;

		/* copy dentry */
		memcpy(pos, ep, sizeof(struct exfat_dentry));

		if (--num_entries == 0)
			break;

		if (((off + DENTRY_SIZE) & (sb->s_blocksize - 1)) <
		    (off & (sb->s_blocksize - 1))) {
	num_bh = EXFAT_B_TO_BLK_ROUND_UP(off + num_entries * DENTRY_SIZE, sb);
	for (i = 1; i < num_bh; i++) {
		/* get the next sector */
		if (exfat_is_last_sector_in_cluster(sbi, sec)) {
				if (es->alloc_flag == ALLOC_NO_FAT_CHAIN)
			if (p_dir->flags == ALLOC_NO_FAT_CHAIN)
				clu++;
			else if (exfat_get_next_cluster(sb, &clu))
				goto free_es;
@@ -918,28 +876,22 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,
			sec++;
		}

			brelse(bh);
		bh = sb_bread(sb, sec);
		if (!bh)
			goto free_es;
			off = 0;
			ep = (struct exfat_dentry *)bh->b_data;
		} else {
			ep++;
			off += DENTRY_SIZE;
		}
		pos++;
		es->bh[es->num_bh++] = bh;
	}

	if (file_ep)
		*file_ep = &es->entries[0];
	brelse(bh);
	/* validiate cached dentries */
	for (i = 1; i < num_entries; i++) {
		ep = exfat_get_dentry_cached(es, i);
		if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode))
			goto free_es;
	}
	return es;

free_es:
	kfree(es);
release_bh:
	brelse(bh);
	exfat_free_dentry_set(es, false);
	return NULL;
}

@@ -1048,7 +1000,7 @@ rewind:
			}

			if (entry_type == TYPE_STREAM) {
				unsigned short name_hash;
				u16 name_hash;

				if (step != DIRENT_STEP_STRM) {
					step = DIRENT_STEP_FILE;
+25 −23
Original line number Diff line number Diff line
@@ -71,10 +71,8 @@ enum {
#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 FAT_CACHE_SIZE		128
#define FAT_CACHE_HASH_SIZE	64
#define BUF_CACHE_SIZE		256
#define BUF_CACHE_HASH_SIZE	64
/* Enough size to hold 256 dentry (even 512 Byte sector) */
#define DIR_CACHE_SIZE		(256*sizeof(struct exfat_dentry)/512+1)

#define EXFAT_HINT_NONE		-1
#define EXFAT_MIN_SUBDIR	2
@@ -139,7 +137,7 @@ struct exfat_dentry_namebuf {
struct exfat_uni_name {
	/* +3 for null and for converting */
	unsigned short name[MAX_NAME_LENGTH + 3];
	unsigned short name_hash;
	u16 name_hash;
	unsigned char name_len;
};

@@ -170,14 +168,12 @@ struct exfat_hint {
};

struct exfat_entry_set_cache {
	/* sector number that contains file_entry */
	sector_t sector;
	/* byte offset in the sector */
	unsigned int offset;
	/* flag in stream entry. 01 for cluster chain, 03 for contig. */
	int alloc_flag;
	struct super_block *sb;
	bool modified;
	unsigned int start_off;
	int num_bh;
	struct buffer_head *bh[DIR_CACHE_SIZE];
	unsigned int num_entries;
	struct exfat_dentry entries[];
};

struct exfat_dir_entry {
@@ -231,7 +227,7 @@ struct exfat_sb_info {
	unsigned int root_dir; /* root dir cluster */
	unsigned int dentries_per_clu; /* num of dentries per cluster */
	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_sectors; /* num of allocation bitmap sectors */
@@ -451,8 +447,7 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir,
		int entry, int order, int num_entries);
int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
		int entry);
int exfat_update_dir_chksum_with_entry_set(struct super_block *sb,
		struct exfat_entry_set_cache *es, int sync);
void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es);
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,
		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,
struct exfat_dentry *exfat_get_dentry(struct super_block *sb,
		struct exfat_chain *p_dir, int entry, struct buffer_head **bh,
		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_chain *p_dir, int entry, unsigned int type,
		struct exfat_dentry **file_ep);
		struct exfat_chain *p_dir, int entry, unsigned int type);
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);

/* inode.c */
@@ -492,8 +489,6 @@ int exfat_nls_to_utf16(struct super_block *sb,
		struct exfat_uni_name *uniname, int *p_lossy);
int exfat_create_upcase_table(struct super_block *sb);
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 */
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)
void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...)
		__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,
		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_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
		u8 *tz, __le16 *time, __le16 *date, u8 *time_ms);
unsigned short exfat_calc_chksum_2byte(void *data, int len,
		unsigned short chksum, int type);
		u8 *tz, __le16 *time, __le16 *date, u8 *time_cs);
u16 exfat_calc_chksum16(void *data, int len, u16 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_chain_set(struct exfat_chain *ec, unsigned int dir,
		unsigned int size, unsigned char flags);
+33 −52
Original line number Diff line number Diff line
@@ -8,12 +8,15 @@

#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 VOL_CLEAN		0x0000
#define VOL_DIRTY		0x0002
#define ERR_MEDIUM		0x0004

#define EXFAT_EOF_CLUSTER	0xFFFFFFFFu
#define EXFAT_BAD_CLUSTER	0xFFFFFFF7u
@@ -55,7 +58,7 @@

/* checksum types */
#define CS_DIR_ENTRY		0
#define CS_PBR_SECTOR		1
#define CS_BOOT_SECTOR		1
#define CS_DEFAULT		2

/* file attributes */
@@ -69,22 +72,18 @@
#define ATTR_RWMASK		(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \
				 ATTR_SUBDIR | ATTR_ARCHIVE)

#define PBR64_JUMP_BOOT_LEN		3
#define PBR64_OEM_NAME_LEN		8
#define PBR64_RESERVED_LEN		53
#define BOOTSEC_JUMP_BOOT_LEN		3
#define BOOTSEC_FS_NAME_LEN		8
#define BOOTSEC_OLDBPB_LEN		53

#define EXFAT_FILE_NAME_LEN		15

/* EXFAT BIOS parameter block (64 bytes) */
struct bpb64 {
	__u8 jmp_boot[PBR64_JUMP_BOOT_LEN];
	__u8 oem_name[PBR64_OEM_NAME_LEN];
	__u8 res_zero[PBR64_RESERVED_LEN];
} __packed;

/* EXFAT EXTEND BIOS parameter block (56 bytes) */
struct bsx64 {
	__le64 vol_offset;
/* EXFAT: Main and Backup Boot Sector (512 bytes) */
struct boot_sector {
	__u8	jmp_boot[BOOTSEC_JUMP_BOOT_LEN];
	__u8	fs_name[BOOTSEC_FS_NAME_LEN];
	__u8	must_be_zero[BOOTSEC_OLDBPB_LEN];
	__le64	partition_offset;
	__le64	vol_length;
	__le32	fat_offset;
	__le32	fat_length;
@@ -92,32 +91,14 @@ struct bsx64 {
	__le32	clu_count;
	__le32	root_cluster;
	__le32	vol_serial;
	__u8 fs_version[2];
	__u8	fs_revision[2];
	__le16	vol_flags;
	__u8	sect_size_bits;
	__u8	sect_per_clus_bits;
	__u8	num_fats;
	__u8 phy_drv_no;
	__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	drv_sel;
	__u8	percent_in_use;
	__u8	reserved[7];
	__u8	boot_code[390];
	__le16	signature;
} __packed;
@@ -136,8 +117,8 @@ struct exfat_dentry {
			__le16 modify_date;
			__le16 access_time;
			__le16 access_date;
			__u8 create_time_ms;
			__u8 modify_time_ms;
			__u8 create_time_cs;
			__u8 modify_time_cs;
			__u8 create_tz;
			__u8 modify_tz;
			__u8 access_tz;
Loading