fs: exfat: sync with v5.8-1arter97

Signed-off-by: engstk <eng.stk@sapo.pt>
This commit is contained in:
engstk 2021-04-30 13:23:50 +01:00 committed by Hannes Ylä-Jääski
parent 89c6789c19
commit d24334a163
29 changed files with 6837 additions and 11814 deletions

View File

@ -1,33 +1,26 @@
# SPDX-License-Identifier: GPL-2.0-or-later
config EXFAT_FS
tristate "exFAT fs support"
depends on BLOCK
tristate "exFAT filesystem support"
select NLS
select NLS_UTF8
select NLS_CODEPAGE_437
select NLS_ISO8859_1
help
If you want to use the exFAT file system, then you must say Y or M
here to inlucde exFAT support. exFAT supports winnt short-name rule.
(winnt: emulate the Windows NT rule for display/create.)
This allows you to mount devices formatted with the exFAT file system.
exFAT is typically used on SD-Cards or USB sticks.
To compile this as a module, choose M here: the module will be called
exfat.
if EXFAT_FS
config EXFAT_DEFAULT_CODEPAGE
int "Default codepage for exFAT"
default 437
help
This option should be set to the codepage of your exFAT filesystems.
config EXFAT_DEFAULT_IOCHARSET
string "Default iocharset for exFAT"
default "utf8"
help
Set this to the default input/output character set you'd
like exFAT to use. It should probably match the character set
that most of your exFAT filesystems use, and can be overridden
with the "iocharset" mount option for exFAT filesystems.
Set this to the default input/output character set to use for
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.
config EXFAT_VIRTUAL_XATTR
bool "Virtual xattr support for exFAT"
@ -44,23 +37,4 @@ config EXFAT_VIRTUAL_XATTR_SELINUX_LABEL
Support for "u:object_r:exfat:s0" was added in Android Pie,
if you're running Oreo or lower, use "u:object_r:vfat:s0" instead.
config EXFAT_DEBUG
bool "enable debug features"
if EXFAT_DEBUG
config EXFAT_DBG_MSG
bool "enable debug messages"
config EXFAT_DBG_BUGON
bool "enable strict BUG_ON() for debugging"
config EXFAT_DBG_WARNON
bool "enable strict WARN_ON() for debugging"
endif # if EXFAT_DEBUG
config EXFAT_UEVENT
bool "enable uevent"
endif # if EXFAT_FS

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Makefile for the linux FAT12/16/32(VFAT)/64(exFAT) filesystem driver.
# Makefile for the linux exFAT filesystem support.
#
ifneq ($(KERNELRELEASE),)
@ -7,8 +8,8 @@ ifneq ($(KERNELRELEASE),)
# DKMS_DEFINE
obj-$(CONFIG_EXFAT_FS) += exfat.o
exfat-objs := super.o core.o core_exfat.o blkdev.o fatent.o cache.o \
nls.o misc.o extent.o xattr.o
exfat-objs := inode.o namei.o dir.o super.o fatent.o cache.o nls.o misc.o \
file.o balloc.o xattr.o
else
# Called from external kernel module build

View File

@ -1,27 +1,23 @@
# exfat-linux
This __exFAT filesystem module for Linux kernel__ is based on `sdFAT` drivers by Samsung, which is used with their smartphone lineups.
The main objective of **exfat-linux** is to provide the best generic kernel drivers for exFAT. That means Samsung-specific modifications such as fat12/16/32 handlings, defrag and etc has been removed to make the code portable.
This __exFAT filesystem module for Linux kernel__ is a backport of the latest Linux mainline's exFAT drivers by Samsung.
This project can be used for everyday Linux users by simply doing `make && make install`. Ubuntu users can simply add a PPA and start using it, without even downloading the code. This can also be directly dropped-in to an existing Linux kernel source for building the filesystem drivers inline, which should be useful for Android kernel developers.
---------------------------------------
[exfat-nofuse]'s development has been stale for more than a year with no clear maintainership. It's also been lacking critical upstream(*which is Samsung*) changes.
[exfat-nofuse]: https://github.com/dorimanx/exfat-nofuse
**exfat-linux** is:
* Based on a totally different and newer base provided by Samsung
* Intended to keep upstream changes constantly merged
* Intended to fix breakage from newer kernels as-soon-as-possible
**exfat-linux** has been tested with all major LTS kernels ranging from 3.4 to 4.19 and the ones Canonical uses for Ubuntu: `3.4`, `3.10`, `3.18`, `4.1`, `4.4`, `4.9`, `4.14`, `4.19` and `4.15`, `5.0`, `5.2`, and `5.3-rc`.
**exfat-linux** has been tested with all major LTS kernels ranging from v4.9 to v5.4 and the ones Canonical uses for Ubuntu: `v4.9`, `v4.14`, `v4.19`, `v5.4` and `v4.15`, `v5.3`, and `v5.6`.
It's also been tested with `x86(i386)`, `x86_64(amd64)`, `arm32(AArch32)` and `arm64(AArch64)`.
Linux kernels since `v5.4` includes an exFAT driver, but it is an extremely outdated version from 2016. This was later revised by Samsung directly with `v5.7`.
People on `v5.7` kernel or higher can just use the bundled exFAT drivers.
People on `v5.4+` are highly recommended to use this drivers.
Support for kernel versions lower than `v4.9` were dropped for easier maintenance. For people interested in exFAT support for said kernels, please use the [old branch](https://github.com/arter97/exfat-linux/tree/old). It still works nicely and it's actively being shipped to production smartphones.
exfat-linux is planned to be maintained until Android devices with `v5.7+` LTS kernel become more common.
## Disclaimer
#### ● Original authorship and copyright: Samsung
@ -68,6 +64,8 @@ This will use DKMS(Dynamic Kernel Module Support) and automatically build exFAT
This will install the module to your __currently running kernel__.
__If you're running a `v5.4+` kernel, it is highly recommended to reboot at this point to prevent the existing staging exFAT drivers to load.__
4. And finally load
`sudo modprobe exfat`
@ -109,6 +107,8 @@ For reference, existing exFAT implementations were tested and compared on a serv
Linux 4.14 was used as higher LTS kernels don't work with [exfat-nofuse] at the time of testing.
__The new base backported from mainline is not benchmarked yet.__
### ● Ramdisk
#### fio sequential I/O
@ -159,24 +159,12 @@ Linux 4.14 was used as higher LTS kernels don't work with [exfat-nofuse] at the
* dmask
* fmask
* allow_utime
* codepage
* iocharset
* quiet
* utf8
* tz
* time_offset
* Please refer to the [vfat](https://github.com/torvalds/linux/blob/master/Documentation/filesystems/vfat.txt)'s documentation.
* namecase
* Passing `namecase=1` as a mount option will make exFAT operate in a case-sensitive mode.
* Default is insensitive mode.
* symlink
* Allow a symlink to be created under exFAT.
* errors=continue
* Keep going on a filesystem error.
@ -193,10 +181,4 @@ Linux 4.14 was used as higher LTS kernels don't work with [exfat-nofuse] at the
* Enable the use of discard/TRIM commands to ensure flash storage doesn't run out of free blocks. This option may introduce latency penalty on file removal operations.
* delayed_meta
* Delay flushing metadata, hence improving performance.
* This is enabled by default, please pass `nodelayed_meta` to disable it.
## Enjoy!

View File

@ -1,265 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#ifndef _EXFAT_API_H
#define _EXFAT_API_H
#include "config.h"
#include "exfat_fs.h"
/* cache size (in number of sectors) */
/* (should be an exponential value of 2) */
#define FAT_CACHE_SIZE 128
#define FAT_CACHE_HASH_SIZE 64
#define BUF_CACHE_SIZE 256
#define BUF_CACHE_HASH_SIZE 64
/* Read-ahead related */
/* First config vars. should be pow of 2 */
#define FCACHE_MAX_RA_SIZE (PAGE_SIZE)
#define DCACHE_MAX_RA_SIZE (128*1024)
/* type values */
#define TYPE_UNUSED 0x0000
#define TYPE_DELETED 0x0001
#define TYPE_INVALID 0x0002
#define TYPE_CRITICAL_PRI 0x0100
#define TYPE_BITMAP 0x0101
#define TYPE_UPCASE 0x0102
#define TYPE_VOLUME 0x0103
#define TYPE_DIR 0x0104
#define TYPE_FILE 0x011F
#define TYPE_SYMLINK 0x015F
#define TYPE_CRITICAL_SEC 0x0200
#define TYPE_STREAM 0x0201
#define TYPE_EXTEND 0x0202
#define TYPE_ACL 0x0203
#define TYPE_BENIGN_PRI 0x0400
#define TYPE_GUID 0x0401
#define TYPE_PADDING 0x0402
#define TYPE_ACLTAB 0x0403
#define TYPE_BENIGN_SEC 0x0800
#define TYPE_ALL 0x0FFF
/* eio values */
#define EXFAT_EIO_NONE (0x00000000)
#define EXFAT_EIO_READ (0x00000001)
#define EXFAT_EIO_WRITE (0x00000002)
#define EXFAT_EIO_BDI (0x00000004)
/* modes for volume allocation unit status */
#define VOL_AU_STAT_TOTAL (0)
#define VOL_AU_STAT_CLEAN (1)
#define VOL_AU_STAT_FULL (2)
/* DOS name structure */
typedef struct {
u8 name[DOS_NAME_LENGTH];
u8 name_case;
} DOS_NAME_T;
/* unicode name structure */
typedef struct {
u16 name[MAX_NAME_LENGTH+3]; /* +3 for null and for converting */
u16 name_hash;
u8 name_len;
} UNI_NAME_T;
/* should be merged it to DATE_TIME_T */
typedef struct {
u16 sec; /* 0 ~ 59 */
u16 min; /* 0 ~ 59 */
u16 hour; /* 0 ~ 23 */
u16 day; /* 1 ~ 31 */
u16 mon; /* 1 ~ 12 */
u16 year; /* 0 ~ 127 (since 1980) */
} TIMESTAMP_T;
typedef struct {
u16 Year;
u16 Month;
u16 Day;
u16 Hour;
u16 Minute;
u16 Second;
u16 MilliSecond;
} DATE_TIME_T;
typedef struct {
u64 Offset; // start sector number of the partition
u64 Size; // in sectors
} PART_INFO_T;
typedef struct {
u32 SecSize; // sector size in bytes
u64 DevSize; // block device size in sectors
} DEV_INFO_T;
typedef struct {
u32 ClusterSize;
u32 NumClusters;
u32 FreeClusters;
u32 UsedClusters;
} VOL_INFO_T;
/* directory structure */
typedef struct {
u32 dir;
u32 size;
u8 flags;
} CHAIN_T;
/* hint structure */
typedef struct {
u32 clu;
union {
u32 off; // cluster offset
s32 eidx; // entry index
};
} HINT_T;
typedef struct {
spinlock_t cache_lru_lock;
struct list_head cache_lru;
s32 nr_caches;
u32 cache_valid_id; // for avoiding the race between alloc and free
} EXTENT_T;
/* first empty entry hint information */
typedef struct {
s32 eidx; // entry index of a directory
s32 count; // count of continuous empty entry
CHAIN_T cur; // the cluster that first empty slot exists in
} HINT_FEMP_T;
/* file id structure */
typedef struct {
CHAIN_T dir;
s32 entry;
u32 type;
u32 attr;
u32 start_clu;
u64 size;
u8 flags;
u8 reserved[3]; // padding
u32 version; // the copy of low 32bit of i_version to check the validation of hint_stat
s64 rwoffset; // file offset or dentry index for readdir
EXTENT_T extent; // extent cache for a file
HINT_T hint_bmap; // hint for cluster last accessed
HINT_T hint_stat; // hint for entry index we try to lookup next time
HINT_FEMP_T hint_femp; // hint for first empty entry
} FILE_ID_T;
typedef struct {
s8 *lfn;
s8 *sfn;
s32 lfnbuf_len; //usally MAX_UNINAME_BUF_SIZE
s32 sfnbuf_len; //usally MAX_DOSNAME_BUF_SIZE, used only for vfat, not for exfat
} DENTRY_NAMEBUF_T;
typedef struct {
u32 Attr;
u64 Size;
u32 NumSubdirs;
DATE_TIME_T CreateTimestamp;
DATE_TIME_T ModifyTimestamp;
DATE_TIME_T AccessTimestamp;
DENTRY_NAMEBUF_T NameBuf;
} DIR_ENTRY_T;
/* cache information */
typedef struct __cache_entry {
struct __cache_entry *next;
struct __cache_entry *prev;
struct {
struct __cache_entry *next;
struct __cache_entry *prev;
} hash;
u64 sec;
u32 flag;
struct buffer_head *bh;
} cache_ent_t;
typedef struct {
s32 (*alloc_cluster)(struct super_block *, u32, CHAIN_T *, s32);
s32 (*free_cluster)(struct super_block *, CHAIN_T *, s32);
s32 (*count_used_clusters)(struct super_block *, u32 *);
s32 (*init_dir_entry)(struct super_block *, CHAIN_T *, s32, u32, u32, u64);
s32 (*init_ext_entry)(struct super_block *, CHAIN_T *, s32, s32, UNI_NAME_T *, DOS_NAME_T *);
s32 (*find_dir_entry)(struct super_block *, FILE_ID_T *, CHAIN_T *, UNI_NAME_T *, s32, DOS_NAME_T *, u32);
s32 (*delete_dir_entry)(struct super_block *, CHAIN_T *, s32, s32, s32);
void (*get_uniname_from_ext_entry)(struct super_block *, CHAIN_T *, s32, u16 *);
s32 (*count_ext_entries)(struct super_block *, CHAIN_T *, s32, DENTRY_T *);
s32 (*calc_num_entries)(UNI_NAME_T *);
s32 (*check_max_dentries)(FILE_ID_T *);
u32 (*get_entry_type)(DENTRY_T *);
void (*set_entry_type)(DENTRY_T *, u32);
u32 (*get_entry_attr)(DENTRY_T *);
void (*set_entry_attr)(DENTRY_T *, u32);
u8 (*get_entry_flag)(DENTRY_T *);
void (*set_entry_flag)(DENTRY_T *, u8);
u32 (*get_entry_clu0)(DENTRY_T *);
void (*set_entry_clu0)(DENTRY_T *, u32);
u64 (*get_entry_size)(DENTRY_T *);
void (*set_entry_size)(DENTRY_T *, u64);
void (*get_entry_time)(DENTRY_T *, TIMESTAMP_T *, u8);
void (*set_entry_time)(DENTRY_T *, TIMESTAMP_T *, u8);
u32 (*get_au_stat)(struct super_block *, s32);
} FS_FUNC_T;
typedef struct __FS_INFO_T {
s32 bd_opened; // opened or not
u32 vol_id; // volume serial number
u64 num_sectors; // num of sectors in volume
u32 num_clusters; // num of clusters in volume
u32 cluster_size; // cluster size in bytes
u32 cluster_size_bits;
u32 sect_per_clus; // cluster size in sectors
u32 sect_per_clus_bits;
u64 FAT1_start_sector; // FAT1 start sector
u64 FAT2_start_sector; // FAT2 start sector
u64 root_start_sector; // root dir start sector
u64 data_start_sector; // data area start sector
u32 num_FAT_sectors; // num of FAT sectors
u32 root_dir; // root dir cluster
u32 dentries_in_root; // num of dentries in root dir
u32 dentries_per_clu; // num of dentries per cluster
u32 vol_flag; // volume dirty flag
struct buffer_head *pbr_bh; // buffer_head of PBR sector
u32 map_clu; // allocation bitmap start cluster
u32 map_sectors; // num of allocation bitmap sectors
struct buffer_head **vol_amap; // allocation bitmap
u16 **vol_utbl; // upcase table
u32 clu_srch_ptr; // cluster search pointer
u32 used_clusters; // number of used clusters
u32 prev_eio; // block device operation error flag
FS_FUNC_T *fs_func;
s32 reserved_clusters; // # of reserved clusters (DA)
void *amap; // AU Allocation Map
/* fat cache */
struct {
cache_ent_t pool[FAT_CACHE_SIZE];
cache_ent_t lru_list;
cache_ent_t hash_list[FAT_CACHE_HASH_SIZE];
} fcache;
/* meta cache */
struct {
cache_ent_t pool[BUF_CACHE_SIZE];
cache_ent_t lru_list;
cache_ent_t keep_list; // CACHEs in this list will not be kicked by normal lru operations
cache_ent_t hash_list[BUF_CACHE_HASH_SIZE];
} dcache;
} FS_INFO_T;
#endif /* _EXFAT_API_H */

274
fs/exfat/balloc.c Normal file
View File

@ -0,0 +1,274 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#include <linux/blkdev.h>
#include <linux/slab.h>
#include <linux/buffer_head.h>
#include "exfat_fs.h"
static const unsigned char free_bit[] = {
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/* 0 ~ 19*/
0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3,/* 20 ~ 39*/
0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/* 40 ~ 59*/
0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/* 60 ~ 79*/
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2,/* 80 ~ 99*/
0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3,/*100 ~ 119*/
0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*120 ~ 139*/
0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,/*140 ~ 159*/
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*160 ~ 179*/
0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3,/*180 ~ 199*/
0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*200 ~ 219*/
0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/*220 ~ 239*/
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /*240 ~ 254*/
};
static const unsigned char used_bit[] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,/* 0 ~ 19*/
2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,/* 20 ~ 39*/
2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,/* 40 ~ 59*/
4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,/* 60 ~ 79*/
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,/* 80 ~ 99*/
3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,/*100 ~ 119*/
4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,/*120 ~ 139*/
3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,/*140 ~ 159*/
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,/*160 ~ 179*/
4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,/*180 ~ 199*/
3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,/*200 ~ 219*/
5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,/*220 ~ 239*/
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /*240 ~ 255*/
};
/*
* Allocation Bitmap Management Functions
*/
static int exfat_allocate_bitmap(struct super_block *sb,
struct exfat_dentry *ep)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
long long map_size;
unsigned int i, need_map_size;
sector_t sector;
sbi->map_clu = le32_to_cpu(ep->dentry.bitmap.start_clu);
map_size = le64_to_cpu(ep->dentry.bitmap.size);
need_map_size = ((EXFAT_DATA_CLUSTER_COUNT(sbi) - 1) / BITS_PER_BYTE)
+ 1;
if (need_map_size != map_size) {
exfat_err(sb, "bogus allocation bitmap size(need : %u, cur : %lld)",
need_map_size, map_size);
/*
* Only allowed when bogus allocation
* bitmap size is large
*/
if (need_map_size > map_size)
return -EIO;
}
sbi->map_sectors = ((need_map_size - 1) >>
(sb->s_blocksize_bits)) + 1;
sbi->vol_amap = kmalloc_array(sbi->map_sectors,
sizeof(struct buffer_head *), GFP_KERNEL);
if (!sbi->vol_amap)
return -ENOMEM;
sector = exfat_cluster_to_sector(sbi, sbi->map_clu);
for (i = 0; i < sbi->map_sectors; i++) {
sbi->vol_amap[i] = sb_bread(sb, sector + i);
if (!sbi->vol_amap[i]) {
/* release all buffers and free vol_amap */
int j = 0;
while (j < i)
brelse(sbi->vol_amap[j++]);
kfree(sbi->vol_amap);
sbi->vol_amap = NULL;
return -EIO;
}
}
return 0;
}
int exfat_load_bitmap(struct super_block *sb)
{
unsigned int i, type;
struct exfat_chain clu;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
exfat_chain_set(&clu, sbi->root_dir, 0, ALLOC_FAT_CHAIN);
while (clu.dir != EXFAT_EOF_CLUSTER) {
for (i = 0; i < sbi->dentries_per_clu; i++) {
struct exfat_dentry *ep;
struct buffer_head *bh;
ep = exfat_get_dentry(sb, &clu, i, &bh, NULL);
if (!ep)
return -EIO;
type = exfat_get_entry_type(ep);
if (type == TYPE_UNUSED)
break;
if (type != TYPE_BITMAP)
continue;
if (ep->dentry.bitmap.flags == 0x0) {
int err;
err = exfat_allocate_bitmap(sb, ep);
brelse(bh);
return err;
}
brelse(bh);
}
if (exfat_get_next_cluster(sb, &clu.dir))
return -EIO;
}
return -EINVAL;
}
void exfat_free_bitmap(struct exfat_sb_info *sbi)
{
int i;
for (i = 0; i < sbi->map_sectors; i++)
__brelse(sbi->vol_amap[i]);
kfree(sbi->vol_amap);
}
/*
* If the value of "clu" is 0, it means cluster 2 which is the first cluster of
* the cluster heap.
*/
int exfat_set_bitmap(struct inode *inode, unsigned int clu)
{
int i, b;
unsigned int ent_idx;
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
WARN_ON(clu < EXFAT_FIRST_CLUSTER);
ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
set_bit_le(b, sbi->vol_amap[i]->b_data);
exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode));
return 0;
}
/*
* If the value of "clu" is 0, it means cluster 2 which is the first cluster of
* the cluster heap.
*/
void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
{
int i, b;
unsigned int ent_idx;
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_mount_options *opts = &sbi->options;
WARN_ON(clu < EXFAT_FIRST_CLUSTER);
ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
clear_bit_le(b, sbi->vol_amap[i]->b_data);
exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode));
if (opts->discard) {
int ret_discard;
ret_discard = sb_issue_discard(sb,
exfat_cluster_to_sector(sbi, clu +
EXFAT_RESERVED_CLUSTERS),
(1 << sbi->sect_per_clus_bits), GFP_NOFS, 0);
if (ret_discard == -EOPNOTSUPP) {
exfat_err(sb, "discard not supported by device, disabling");
opts->discard = 0;
}
}
}
/*
* If the value of "clu" is 0, it means cluster 2 which is the first cluster of
* the cluster heap.
*/
unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu)
{
unsigned int i, map_i, map_b, ent_idx;
unsigned int clu_base, clu_free;
unsigned char k, clu_mask;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
WARN_ON(clu < EXFAT_FIRST_CLUSTER);
ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx & ~(BITS_PER_BYTE_MASK));
clu_mask = IGNORED_BITS_REMAINED(clu, clu_base);
map_i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
map_b = BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent_idx);
for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters;
i += BITS_PER_BYTE) {
k = *(sbi->vol_amap[map_i]->b_data + map_b);
if (clu_mask > 0) {
k |= clu_mask;
clu_mask = 0;
}
if (k < 0xFF) {
clu_free = clu_base + free_bit[k];
if (clu_free < sbi->num_clusters)
return clu_free;
}
clu_base += BITS_PER_BYTE;
if (++map_b >= sb->s_blocksize ||
clu_base >= sbi->num_clusters) {
if (++map_i >= sbi->map_sectors) {
clu_base = EXFAT_FIRST_CLUSTER;
map_i = 0;
}
map_b = 0;
}
}
return EXFAT_EOF_CLUSTER;
}
int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
unsigned int count = 0;
unsigned int i, map_i = 0, map_b = 0;
unsigned int total_clus = EXFAT_DATA_CLUSTER_COUNT(sbi);
unsigned int last_mask = total_clus & BITS_PER_BYTE_MASK;
unsigned char clu_bits;
const unsigned char last_bit_mask[] = {0, 0b00000001, 0b00000011,
0b00000111, 0b00001111, 0b00011111, 0b00111111, 0b01111111};
total_clus &= ~last_mask;
for (i = 0; i < total_clus; i += BITS_PER_BYTE) {
clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b);
count += used_bit[clu_bits];
if (++map_b >= (unsigned int)sb->s_blocksize) {
map_i++;
map_b = 0;
}
}
if (last_mask) {
clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b);
clu_bits &= last_bit_mask[last_mask];
count += used_bit[clu_bits];
}
*ret_count = count;
return 0;
}

View File

@ -1,318 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*
* blkdev.c: exFAT Block Device Driver Glue Layer
*/
#include <linux/blkdev.h>
#include <linux/log2.h>
#include <linux/backing-dev.h>
#include "exfat.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
/* EMPTY */
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) */
static struct backing_dev_info *inode_to_bdi(struct inode *bd_inode)
{
return bd_inode->i_mapping->backing_dev_info;
}
#endif
s32 exfat_bdev_open_dev(struct super_block *sb)
{
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
if (fsi->bd_opened)
return 0;
fsi->bd_opened = true;
return 0;
}
s32 exfat_bdev_close_dev(struct super_block *sb)
{
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
fsi->bd_opened = false;
return 0;
}
static inline s32 block_device_ejected(struct super_block *sb)
{
struct inode *bd_inode = sb->s_bdev->bd_inode;
struct backing_dev_info *bdi = inode_to_bdi(bd_inode);
return (bdi->dev == NULL);
}
s32 exfat_bdev_check_bdi_valid(struct super_block *sb)
{
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
if (block_device_ejected(sb)) {
if (!(fsi->prev_eio & EXFAT_EIO_BDI)) {
fsi->prev_eio |= EXFAT_EIO_BDI;
exfat_log_msg(sb, KERN_ERR, "%s: block device is "
"eliminated.(bdi:%p)", __func__, sb->s_bdi);
exfat_debug_warn_on(1);
}
return -ENXIO;
}
return 0;
}
/* Make a readahead request */
s32 exfat_bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs)
{
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
u32 sects_per_page = (PAGE_SIZE >> sb->s_blocksize_bits);
struct blk_plug plug;
u64 i;
if (!fsi->bd_opened)
return -EIO;
blk_start_plug(&plug);
for (i = 0; i < num_secs; i++) {
if (i && !(i & (sects_per_page - 1))) {
#ifdef MODULE
/* TODO: fix this by using proper APIs */
blk_finish_plug(&plug);
blk_start_plug(&plug);
#else
blk_flush_plug(current);
#endif
}
sb_breadahead(sb, (sector_t)(secno + i));
}
blk_finish_plug(&plug);
return 0;
}
s32 exfat_bdev_mread(struct super_block *sb, u64 secno, struct buffer_head **bh, u64 num_secs, s32 read)
{
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
u8 blksize_bits = sb->s_blocksize_bits;
if (!fsi->bd_opened)
return -EIO;
brelse(*bh);
if (read)
*bh = __bread(sb->s_bdev, (sector_t)secno, num_secs << blksize_bits);
else
*bh = __getblk(sb->s_bdev, (sector_t)secno, num_secs << blksize_bits);
/* read successfully */
if (*bh)
return 0;
/*
* patch 1.2.4 : reset ONCE warning message per volume.
*/
if (!(fsi->prev_eio & EXFAT_EIO_READ)) {
fsi->prev_eio |= EXFAT_EIO_READ;
exfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__);
exfat_debug_warn_on(1);
}
return -EIO;
}
s32 exfat_bdev_mwrite(struct super_block *sb, u64 secno, struct buffer_head *bh, u64 num_secs, s32 sync)
{
u64 count;
struct buffer_head *bh2;
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
if (!fsi->bd_opened)
return -EIO;
if (secno == bh->b_blocknr) {
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
if (sync && (sync_dirty_buffer(bh) != 0))
return -EIO;
} else {
count = num_secs << sb->s_blocksize_bits;
bh2 = __getblk(sb->s_bdev, (sector_t)secno, count);
if (!bh2)
goto no_bh;
lock_buffer(bh2);
memcpy(bh2->b_data, bh->b_data, count);
set_buffer_uptodate(bh2);
mark_buffer_dirty(bh2);
unlock_buffer(bh2);
if (sync && (sync_dirty_buffer(bh2) != 0)) {
__brelse(bh2);
goto no_bh;
}
__brelse(bh2);
}
return 0;
no_bh:
/*
* patch 1.2.4 : reset ONCE warning message per volume.
*/
if (!(fsi->prev_eio & EXFAT_EIO_WRITE)) {
fsi->prev_eio |= EXFAT_EIO_WRITE;
exfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__);
exfat_debug_warn_on(1);
}
return -EIO;
}
s32 exfat_bdev_sync_all(struct super_block *sb)
{
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
if (!fsi->bd_opened)
return -EIO;
return sync_blockdev(sb->s_bdev);
}
/*
* Sector Read/Write Functions
*/
s32 exfat_read_sect(struct super_block *sb, u64 sec, struct buffer_head **bh, s32 read)
{
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
BUG_ON(!bh);
if ((sec >= fsi->num_sectors) && (fsi->num_sectors > 0)) {
exfat_fs_error_ratelimit(sb,
"%s: out of range (sect:%llu)", __func__, sec);
return -EIO;
}
if (exfat_bdev_mread(sb, sec, bh, 1, read)) {
exfat_fs_error_ratelimit(sb,
"%s: I/O error (sect:%llu)", __func__, sec);
return -EIO;
}
return 0;
}
s32 exfat_write_sect(struct super_block *sb, u64 sec, struct buffer_head *bh, s32 sync)
{
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
BUG_ON(!bh);
if ((sec >= fsi->num_sectors) && (fsi->num_sectors > 0)) {
exfat_fs_error_ratelimit(sb,
"%s: out of range (sect:%llu)", __func__, sec);
return -EIO;
}
if (exfat_bdev_mwrite(sb, sec, bh, 1, sync)) {
exfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%llu)",
__func__, sec);
return -EIO;
}
return 0;
}
static inline void __blkdev_write_bhs(struct buffer_head **bhs, s32 nr_bhs)
{
s32 i;
for (i = 0; i < nr_bhs; i++)
write_dirty_buffer(bhs[i], WRITE);
}
static inline s32 __blkdev_sync_bhs(struct buffer_head **bhs, s32 nr_bhs)
{
s32 i, err = 0;
for (i = 0; i < nr_bhs; i++) {
wait_on_buffer(bhs[i]);
if (!err && !buffer_uptodate(bhs[i]))
err = -EIO;
}
return err;
}
static inline s32 __buffer_zeroed(struct super_block *sb, u64 blknr, u64 num_secs)
{
struct buffer_head *bhs[MAX_BUF_PER_PAGE];
s32 nr_bhs = MAX_BUF_PER_PAGE;
u64 last_blknr = blknr + num_secs;
s32 err, i, n;
struct blk_plug plug;
/* Zeroing the unused blocks on this cluster */
n = 0;
blk_start_plug(&plug);
while (blknr < last_blknr) {
bhs[n] = sb_getblk(sb, (sector_t)blknr);
if (!bhs[n]) {
err = -ENOMEM;
blk_finish_plug(&plug);
goto error;
}
memset(bhs[n]->b_data, 0, sb->s_blocksize);
set_buffer_uptodate(bhs[n]);
mark_buffer_dirty(bhs[n]);
n++;
blknr++;
if (blknr == last_blknr)
break;
if (n == nr_bhs) {
__blkdev_write_bhs(bhs, n);
for (i = 0; i < n; i++)
brelse(bhs[i]);
n = 0;
}
}
__blkdev_write_bhs(bhs, n);
blk_finish_plug(&plug);
err = __blkdev_sync_bhs(bhs, n);
if (err)
goto error;
for (i = 0; i < n; i++)
brelse(bhs[i]);
return 0;
error:
EMSG("%s: failed zeroed sect %llu\n", __func__, blknr);
for (i = 0; i < n; i++)
bforget(bhs[i]);
return err;
}
s32 exfat_write_msect_zero(struct super_block *sb, u64 sec, u64 num_secs)
{
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
if (((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0)) {
exfat_fs_error_ratelimit(sb, "%s: out of range(sect:%llu len:%llu)",
__func__, sec, num_secs);
return -EIO;
}
/* Just return -EAGAIN if it is failed */
if (__buffer_zeroed(sb, sec, num_secs))
return -EAGAIN;
return 0;
}

File diff suppressed because it is too large Load Diff

48
fs/exfat/compat.h Normal file
View File

@ -0,0 +1,48 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#ifndef _EXFAT_COMPAT_H
#define _EXFAT_COMPAT_H
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
#error "This driver doesn't support v5.8+, " \
"please use the included driver from your kernel"
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
#error "This driver doesn't support kernel versions lower than v4.9, " \
"please use the driver from https://github.com/arter97/exfat-linux/tree/old"
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
#include <linux/iversion.h>
#else
#define inode_inc_iversion(inode) (inode->i_version++)
#define inode_query_iversion(inode) (inode->i_version)
#define inode_eq_iversion(inode, version) (inode->i_version == version)
#define inode_peek_iversion_raw(inode) (inode->i_version)
#define inode_set_iversion(inode, val) (inode->i_version = val)
#endif
/* MS flags were renamed to SB on v4.15 */
#ifndef SB_NODIRATIME
#define SB_NODIRATIME MS_NODIRATIME
#endif
#ifndef SB_RDONLY
#define SB_RDONLY MS_RDONLY
#endif
#ifndef SB_SYNCHRONOUS
#define SB_SYNCHRONOUS MS_SYNCHRONOUS
#endif
#ifndef sb_rdonly
#define sb_rdonly(sb) ((sb)->s_flags & SB_RDONLY)
#endif
#endif /* _EXFAT_COMPAT_H */

View File

@ -6,20 +6,8 @@
#ifndef _EXFAT_CONFIG_H
#define _EXFAT_CONFIG_H
#ifndef CONFIG_EXFAT_WRITE_SB_INTERVAL_CSECS
#define CONFIG_EXFAT_WRITE_SB_INTERVAL_CSECS (dirty_writeback_interval)
#endif
#ifndef CONFIG_EXFAT_DEFAULT_CODEPAGE /* if Kconfig lacked codepage */
#define CONFIG_EXFAT_DEFAULT_CODEPAGE 437
#endif
#ifndef CONFIG_EXFAT_DEFAULT_IOCHARSET /* if Kconfig lacked iocharset */
#define CONFIG_EXFAT_DEFAULT_IOCHARSET "utf8"
#endif
#ifndef CONFIG_EXFAT_VIRTUAL_XATTR
#define CONFIG_EXFAT_VIRTUAL_XATTR
#endif
#endif /* _EXFAT_CONFIG_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,149 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#ifndef _EXFAT_CORE_H
#define _EXFAT_CORE_H
#include <asm/byteorder.h>
#include "config.h"
#include "api.h"
#include "upcase.h"
#define get_next_clus(sb, pclu) exfat_ent_get(sb, *(pclu), pclu)
#define get_next_clus_safe(sb, pclu) exfat_ent_get_safe(sb, *(pclu), pclu)
/* file status */
/* this prevents
* exfat_fscore_write_inode, exfat_fscore_map_clus, ... with the unlinked inodes
* from corrupting on-disk dentry data.
*
* The fid->dir value of unlinked inode will be DIR_DELETED
* and those functions must check if fid->dir is valid prior to
* the calling of exfat_get_dentry_in_dir()
*/
#define DIR_DELETED 0xFFFF0321
#define ES_2_ENTRIES 2
#define ES_3_ENTRIES 3
#define ES_ALL_ENTRIES 0
typedef struct {
u64 sector; // sector number that contains file_entry
u32 offset; // byte offset in the sector
s32 alloc_flag; // flag in stream entry. 01 for cluster chain, 03 for contig. clusters.
u32 num_entries;
void *__buf; // __buf should be the last member
} ENTRY_SET_CACHE_T;
/* file system initialization & shutdown functions */
s32 exfat_fscore_init(void);
s32 exfat_fscore_shutdown(void);
/* bdev management */
s32 exfat_fscore_check_bdi_valid(struct super_block *sb);
/* chain management */
s32 exfat_chain_cont_cluster(struct super_block *sb, u32 chain, u32 len);
/* volume management functions */
s32 exfat_fscore_mount(struct super_block *sb);
s32 exfat_fscore_umount(struct super_block *sb);
s32 exfat_fscore_statfs(struct super_block *sb, VOL_INFO_T *info);
s32 exfat_fscore_sync_fs(struct super_block *sb, s32 do_sync);
s32 exfat_fscore_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_sync);
u32 exfat_fscore_get_au_stat(struct super_block *sb, s32 mode);
/* file management functions */
s32 exfat_fscore_lookup(struct inode *inode, u8 *path, FILE_ID_T *fid);
s32 exfat_fscore_create(struct inode *inode, u8 *path, u8 mode, FILE_ID_T *fid);
s32 exfat_fscore_read_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount);
s32 exfat_fscore_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount);
s32 exfat_fscore_truncate(struct inode *inode, u64 old_size, u64 new_size);
s32 exfat_fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid,
struct inode *new_parent_inode, struct dentry *new_dentry);
s32 exfat_fscore_remove(struct inode *inode, FILE_ID_T *fid);
s32 exfat_fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info);
s32 exfat_fscore_write_inode(struct inode *inode, DIR_ENTRY_T *info, int sync);
s32 exfat_fscore_map_clus(struct inode *inode, u32 clu_offset, u32 *clu, int dest);
s32 exfat_fscore_unlink(struct inode *inode, FILE_ID_T *fid);
/* directory management functions */
s32 exfat_fscore_mkdir(struct inode *inode, u8 *path, FILE_ID_T *fid);
s32 exfat_fscore_readdir(struct inode *inode, DIR_ENTRY_T *dir_ent);
s32 exfat_fscore_rmdir(struct inode *inode, FILE_ID_T *fid);
/* core.c : core code for common */
/* dir entry management functions */
DENTRY_T *exfat_get_dentry_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u64 *sector);
/* name conversion functions */
void exfat_get_uniname_from_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, UNI_NAME_T *p_uniname, u8 mode);
/* file operation functions */
s32 exfat_walk_fat_chain(struct super_block *sb, CHAIN_T *p_dir, u32 byte_offset, u32 *clu);
/* exfat/cache.c */
s32 exfat_meta_cache_init(struct super_block *sb);
s32 exfat_meta_cache_shutdown(struct super_block *sb);
u8 *exfat_fcache_getblk(struct super_block *sb, u64 sec);
s32 exfat_fcache_modify(struct super_block *sb, u64 sec);
s32 exfat_fcache_release_all(struct super_block *sb);
s32 exfat_fcache_flush(struct super_block *sb, u32 sync);
u8 *exfat_dcache_getblk(struct super_block *sb, u64 sec);
s32 exfat_dcache_modify(struct super_block *sb, u64 sec);
s32 exfat_dcache_lock(struct super_block *sb, u64 sec);
s32 exfat_dcache_unlock(struct super_block *sb, u64 sec);
s32 exfat_dcache_release(struct super_block *sb, u64 sec);
s32 exfat_dcache_release_all(struct super_block *sb);
s32 exfat_dcache_flush(struct super_block *sb, u32 sync);
s32 exfat_dcache_readahead(struct super_block *sb, u64 sec);
/* fatent.c */
s32 exfat_ent_get(struct super_block *sb, u32 loc, u32 *content);
s32 exfat_ent_set(struct super_block *sb, u32 loc, u32 content);
s32 exfat_ent_get_safe(struct super_block *sb, u32 loc, u32 *content);
/* core_exfat.c : core code for exfat */
s32 exfat_load_alloc_bmp(struct super_block *sb);
void exfat_free_alloc_bmp(struct super_block *sb);
ENTRY_SET_CACHE_T *exfat_get_dentry_set_in_dir(struct super_block *sb,
CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep);
void exfat_release_dentry_set(ENTRY_SET_CACHE_T *es);
s32 exfat_update_dir_chksum(struct super_block *sb, CHAIN_T *p_dir, s32 entry);
s32 exfat_update_dir_chksum_with_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es);
s32 mount_exfat(struct super_block *sb, pbr_t *p_pbr);
/* blkdev.c */
s32 exfat_bdev_open_dev(struct super_block *sb);
s32 exfat_bdev_close_dev(struct super_block *sb);
s32 exfat_bdev_check_bdi_valid(struct super_block *sb);
s32 exfat_bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs);
s32 exfat_bdev_mread(struct super_block *sb, u64 secno, struct buffer_head **bh, u64 num_secs, s32 read);
s32 exfat_bdev_mwrite(struct super_block *sb, u64 secno, struct buffer_head *bh, u64 num_secs, s32 sync);
s32 exfat_bdev_sync_all(struct super_block *sb);
/* blkdev.c : sector read/write functions */
s32 exfat_read_sect(struct super_block *sb, u64 sec, struct buffer_head **bh, s32 read);
s32 exfat_write_sect(struct super_block *sb, u64 sec, struct buffer_head *bh, s32 sync);
s32 exfat_write_msect_zero(struct super_block *sb, u64 sec, u64 num_secs);
/* misc.c */
u16 exfat_calc_chksum_2byte(void *data, s32 len, u16 chksum, s32 type);
/* extent.c */
s32 exfat_extent_cache_init(void);
void exfat_extent_cache_shutdown(void);
void exfat_extent_cache_init_inode(struct inode *inode);
void exfat_extent_cache_inval_inode(struct inode *inode);
s32 exfat_extent_get_clus(struct inode *inode, u32 cluster, u32 *fclus,
u32 *dclus, u32 *last_dclus, s32 allow_eof);
void exfat_set_sb_dirty(struct super_block *sb);
#endif /* _EXFAT_CORE_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,18 @@
exfat-dkms (5.8~2arter97) UNRELEASED; urgency=medium
* Applied fixes from Linux v5.8-rc4
* Fixed sanity-checks on allow_utime and discard mount options
* Added build-time error messages for unsupported kernel versions
-- Park Ju Hyung <qkrwngud825@gmail.com> Wed, 01 Jul 2020 02:47:26 +0900
exfat-dkms (5.8~1arter97) UNRELEASED; urgency=medium
* Rebased to Linux mainline's drivers
* Supports for kernels lower than v4.9 dropped
-- Park Ju Hyung <qkrwngud825@gmail.com> Sat, 27 Jun 2020 08:32:23 +0900
exfat-dkms (2.2.0-3arter97) UNRELEASED; urgency=medium
* Added "quiet" mount option.

View File

@ -2,7 +2,7 @@
include /usr/share/dpkg/pkg-info.mk
version := $(shell dpkg-parsechangelog | grep '^Version:' | cut -d' ' -f2)
version := $(shell echo $(DEB_VERSION_UPSTREAM) | sed -e 's/~[^~]*$$//')
targetdir := debian/tmp/usr/src/exfat-$(version)
%:

1191
fs/exfat/dir.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,389 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#ifndef _EXFAT_H
#define _EXFAT_H
#include <linux/buffer_head.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/nls.h>
#include <linux/fs.h>
#include <linux/mutex.h>
#include <linux/ratelimit.h>
#include <linux/version.h>
#include <linux/kobject.h>
#include "api.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
#include <linux/iversion.h>
#define INC_IVERSION(x) (inode_inc_iversion(x))
#define GET_IVERSION(x) (inode_peek_iversion_raw(x))
#define SET_IVERSION(x,y) (inode_set_iversion(x, y))
#else
#define INC_IVERSION(x) (x->i_version++)
#define GET_IVERSION(x) (x->i_version)
#define SET_IVERSION(x,y) (x->i_version = y)
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
#define timespec_compat timespec64
#define KTIME_GET_REAL_TS ktime_get_real_ts64
#else
#define timespec_compat timespec
#define KTIME_GET_REAL_TS ktime_get_real_ts
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
#define EXFAT_IS_SB_RDONLY(sb) ((sb)->s_flags & MS_RDONLY)
#else
#define EXFAT_IS_SB_RDONLY(sb) ((sb)->s_flags & SB_RDONLY)
#endif
/*
* exfat error flags
*/
#define EXFAT_ERRORS_CONT (1) /* ignore error and continue */
#define EXFAT_ERRORS_PANIC (2) /* panic on error */
#define EXFAT_ERRORS_RO (3) /* remount r/o on error */
/*
* exfat allocator destination for smart allocation
*/
#define ALLOC_NOWHERE (0)
#define ALLOC_COLD (1)
#define ALLOC_HOT (16)
#define ALLOC_COLD_ALIGNED (1)
#define ALLOC_COLD_PACKING (2)
#define ALLOC_COLD_SEQ (4)
/*
* exfat nls lossy flag
*/
#define NLS_NAME_NO_LOSSY (0x00) /* no lossy */
#define NLS_NAME_LOSSY (0x01) /* just detected incorrect filename(s) */
#define NLS_NAME_OVERLEN (0x02) /* the length is over than its limit */
/*
* exfat common MACRO
*/
#define CLUSTER_16(x) ((u16)((x) & 0xFFFFU))
#define CLUSTER_32(x) ((u32)((x) & 0xFFFFFFFFU))
#define CLUS_EOF CLUSTER_32(~0)
#define CLUS_BAD (0xFFFFFFF7U)
#define CLUS_FREE (0)
#define CLUS_BASE (2)
#define IS_CLUS_EOF(x) ((x) == CLUS_EOF)
#define IS_CLUS_BAD(x) ((x) == CLUS_BAD)
#define IS_CLUS_FREE(x) ((x) == CLUS_FREE)
#define IS_LAST_SECT_IN_CLUS(fsi, sec) \
((((sec) - (fsi)->data_start_sector + 1) \
& ((1 << (fsi)->sect_per_clus_bits) - 1)) == 0)
#define CLUS_TO_SECT(fsi, x) \
((((unsigned long long)(x) - CLUS_BASE) << (fsi)->sect_per_clus_bits) + (fsi)->data_start_sector)
#define SECT_TO_CLUS(fsi, sec) \
((u32)((((sec) - (fsi)->data_start_sector) >> (fsi)->sect_per_clus_bits) + CLUS_BASE))
/*
* exfat mount in-memory data
*/
struct exfat_mount_options {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
kuid_t fs_uid;
kgid_t fs_gid;
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) */
uid_t fs_uid;
gid_t fs_gid;
#endif
unsigned short fs_fmask;
unsigned short fs_dmask;
unsigned short allow_utime; /* permission for setting the [am]time */
unsigned short codepage; /* codepage for shortname conversions */
char *iocharset; /* charset for filename input/display */
unsigned char quiet; /* fake return success on setattr(e.g. chmods/chowns) */
unsigned char utf8;
unsigned char casesensitive;
unsigned char tz_utc;
unsigned char symlink; /* support symlink operation */
unsigned char errors; /* on error: continue, panic, remount-ro */
unsigned char discard; /* flag on if -o dicard specified and device support discard() */
unsigned char delayed_meta; /* delay flushing dirty metadata */
};
#define EXFAT_HASH_BITS 8
#define EXFAT_HASH_SIZE (1UL << EXFAT_HASH_BITS)
/*
* EXFAT file system superblock in-memory data
*/
struct exfat_sb_info {
FS_INFO_T fsi; /* private filesystem info */
struct mutex s_vlock; /* volume lock */
int use_vmalloc;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
int s_dirt;
struct mutex s_lock; /* superblock lock */
int write_super_queued; /* Write_super work is pending? */
struct delayed_work write_super_work; /* Work_queue data structrue for write_super() */
spinlock_t work_lock; /* Lock for WQ */
#endif
struct super_block *host_sb; /* sb pointer */
struct exfat_mount_options options;
struct nls_table *nls_disk; /* Codepage used on disk */
struct nls_table *nls_io; /* Charset used for input and display */
struct ratelimit_state ratelimit;
spinlock_t inode_hash_lock;
struct hlist_head inode_hashtable[EXFAT_HASH_SIZE];
struct kobject sb_kobj;
atomic_t stat_n_pages_queued; /* # of pages in the request queue (approx.) */
};
/*
* EXFAT file system inode in-memory data
*/
struct exfat_inode_info {
FILE_ID_T fid;
char *target;
/* NOTE: i_size_ondisk is 64bits, so must hold ->inode_lock to access */
loff_t i_size_ondisk; /* physically allocated size */
loff_t i_size_aligned; /* block-aligned i_size (used in cont_write_begin) */
loff_t i_pos; /* on-disk position of directory entry or 0 */
struct hlist_node i_hash_fat; /* hash by i_location */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
struct rw_semaphore truncate_lock; /* protect bmap against truncate */
#endif
struct inode vfs_inode;
};
/*
* FIXME : needs on-disk-slot in-memory data
*/
static inline struct exfat_sb_info *EXFAT_SB(struct super_block *sb)
{
return (struct exfat_sb_info *)sb->s_fs_info;
}
static inline struct exfat_inode_info *EXFAT_I(struct inode *inode)
{
return container_of(inode, struct exfat_inode_info, vfs_inode);
}
/*
* If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to
* save ATTR_RO instead of ->i_mode.
*
* If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only
* bit, it's just used as flag for app.
*/
static inline int exfat_mode_can_hold_ro(struct inode *inode)
{
struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
if (S_ISDIR(inode->i_mode))
return 0;
if ((~sbi->options.fs_fmask) & S_IWUGO)
return 1;
return 0;
}
/*
* FIXME : needs to check symlink option.
*/
/* Convert attribute bits and a mask to the UNIX mode. */
static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi,
u32 attr, mode_t mode)
{
if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR))
mode &= ~S_IWUGO;
if (attr & ATTR_SUBDIR)
return (mode & ~sbi->options.fs_dmask) | S_IFDIR;
else if (attr & ATTR_SYMLINK)
return (mode & ~sbi->options.fs_dmask) | S_IFLNK;
else
return (mode & ~sbi->options.fs_fmask) | S_IFREG;
}
/* Return the FAT attribute byte for this inode */
static inline u32 exfat_make_attr(struct inode *inode)
{
u32 attrs = EXFAT_I(inode)->fid.attr;
if (S_ISDIR(inode->i_mode))
attrs |= ATTR_SUBDIR;
if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & S_IWUGO))
attrs |= ATTR_READONLY;
return attrs;
}
static inline void exfat_save_attr(struct inode *inode, u32 attr)
{
if (exfat_mode_can_hold_ro(inode))
EXFAT_I(inode)->fid.attr = attr & ATTR_RWMASK;
else
EXFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY);
}
/* exfat/nls.c */
/* NLS management function */
s32 exfat_nls_cmp_uniname(struct super_block *sb, u16 *a, u16 *b);
s32 exfat_nls_sfn_to_uni16s(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname);
s32 exfat_nls_uni16s_to_vfsname(struct super_block *sb, UNI_NAME_T *uniname, u8 *p_cstring, s32 len);
s32 exfat_nls_vfsname_to_uni16s(struct super_block *sb, const u8 *p_cstring,
const s32 len, UNI_NAME_T *uniname, s32 *p_lossy);
/* exfat/xattr.c */
#ifdef CONFIG_EXFAT_VIRTUAL_XATTR
void setup_exfat_xattr_handler(struct super_block *sb);
extern int exfat_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags);
extern ssize_t exfat_getxattr(struct dentry *dentry, const char *name, void *value, size_t size);
extern ssize_t exfat_listxattr(struct dentry *dentry, char *list, size_t size);
extern int exfat_removexattr(struct dentry *dentry, const char *name);
#else
static inline void setup_exfat_xattr_handler(struct super_block *sb) {};
#endif
/* exfat/misc.c */
#ifdef CONFIG_EXFAT_UEVENT
extern int exfat_uevent_init(struct kset *exfat_kset);
extern void exfat_uevent_uninit(void);
extern void exfat_uevent_ro_remount(struct super_block *sb);
#else
static inline int exfat_uevent_init(struct kset *exfat_kset)
{
return 0;
}
static inline void exfat_uevent_uninit(void) {};
static inline void exfat_uevent_ro_remount(struct super_block *sb) {};
#endif
extern void
__exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
__printf(3, 4) __cold;
#define exfat_fs_error(sb, fmt, args...) \
__exfat_fs_error(sb, 1, fmt, ## args)
#define exfat_fs_error_ratelimit(sb, fmt, args...) \
__exfat_fs_error(sb, __ratelimit(&EXFAT_SB(sb)->ratelimit), fmt, ## args)
extern void
__exfat_msg(struct super_block *sb, const char *lv, int st, const char *fmt, ...)
__printf(4, 5) __cold;
#define exfat_msg(sb, lv, fmt, args...) \
__exfat_msg(sb, lv, 0, fmt, ## args)
#define exfat_log_msg(sb, lv, fmt, args...) \
__exfat_msg(sb, lv, 1, fmt, ## args)
extern void exfat_log_version(void);
extern void exfat_time_fat2unix(struct exfat_sb_info *sbi, struct timespec_compat *ts,
DATE_TIME_T *tp);
extern void exfat_time_unix2fat(struct exfat_sb_info *sbi, struct timespec_compat *ts,
DATE_TIME_T *tp);
extern TIMESTAMP_T *exfat_tm_now(struct exfat_sb_info *sbi, TIMESTAMP_T *tm);
#ifdef CONFIG_EXFAT_DEBUG
#ifdef CONFIG_EXFAT_DBG_BUGON
#define exfat_debug_bug_on(expr) BUG_ON(expr)
#else
#define exfat_debug_bug_on(expr)
#endif
#ifdef CONFIG_EXFAT_DBG_WARNON
#define exfat_debug_warn_on(expr) WARN_ON(expr)
#else
#define exfat_debug_warn_on(expr)
#endif
#else /* CONFIG_EXFAT_DEBUG */
#define exfat_debug_bug_on(expr)
#define exfat_debug_warn_on(expr)
#endif /* CONFIG_EXFAT_DEBUG */
#define EXFAT_MSG_LV_NONE (0x00000000)
#define EXFAT_MSG_LV_ERR (0x00000001)
#define EXFAT_MSG_LV_INFO (0x00000002)
#define EXFAT_MSG_LV_DBG (0x00000003)
#define EXFAT_MSG_LV_MORE (0x00000004)
#define EXFAT_MSG_LV_TRACE (0x00000005)
#define EXFAT_MSG_LV_ALL (0x00000006)
#define EXFAT_MSG_LEVEL EXFAT_MSG_LV_INFO
#define EXFAT_TAG_NAME "EXFAT"
#define __S(x) #x
#define _S(x) __S(x)
extern void __exfat_dmsg(int level, const char *fmt, ...) __printf(2, 3) __cold;
#define EXFAT_EMSG_T(level, ...) \
__exfat_dmsg(level, KERN_ERR "[" EXFAT_TAG_NAME "] [" _S(__FILE__) "(" _S(__LINE__) ")] " __VA_ARGS__)
#define EXFAT_DMSG_T(level, ...) \
__exfat_dmsg(level, KERN_INFO "[" EXFAT_TAG_NAME "] " __VA_ARGS__)
#define EXFAT_EMSG(...) EXFAT_EMSG_T(EXFAT_MSG_LV_ERR, __VA_ARGS__)
#define EXFAT_IMSG(...) EXFAT_DMSG_T(EXFAT_MSG_LV_INFO, __VA_ARGS__)
#define EXFAT_DMSG(...) EXFAT_DMSG_T(EXFAT_MSG_LV_DBG, __VA_ARGS__)
#define EXFAT_MMSG(...) EXFAT_DMSG_T(EXFAT_MSG_LV_MORE, __VA_ARGS__)
#define EMSG(...)
#define IMSG(...)
#define DMSG(...)
#define MMSG(...)
#define EMSG_VAR(exp)
#define IMSG_VAR(exp)
#define DMSG_VAR(exp)
#define MMSG_VAR(exp)
#ifdef CONFIG_EXFAT_DBG_MSG
#if (EXFAT_MSG_LEVEL >= EXFAT_MSG_LV_ERR)
#undef EMSG
#undef EMSG_VAR
#define EMSG(...) EXFAT_EMSG(__VA_ARGS__)
#define EMSG_VAR(exp) exp
#endif
#if (EXFAT_MSG_LEVEL >= EXFAT_MSG_LV_INFO)
#undef IMSG
#undef IMSG_VAR
#define IMSG(...) EXFAT_IMSG(__VA_ARGS__)
#define IMSG_VAR(exp) exp
#endif
#if (EXFAT_MSG_LEVEL >= EXFAT_MSG_LV_DBG)
#undef DMSG
#undef DMSG_VAR
#define DMSG(...) EXFAT_DMSG(__VA_ARGS__)
#define DMSG_VAR(exp) exp
#endif
#if (EXFAT_MSG_LEVEL >= EXFAT_MSG_LV_MORE)
#undef MMSG
#undef MMSG_VAR
#define MMSG(...) EXFAT_MMSG(__VA_ARGS__)
#define MMSG_VAR(exp) exp
#endif
#endif /* CONFIG_EXFAT_DBG_MSG */
#define ASSERT(expr) { \
if (!(expr)) { \
pr_err("exFAT: Assertion failed! %s\n", #expr); \
BUG_ON(1); \
} \
}
#endif /* !_EXFAT_H */

View File

@ -1,377 +1,545 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#ifndef _EXFAT_FS_H
#define _EXFAT_FS_H
#include <linux/types.h>
#include <linux/magic.h>
#include <asm/byteorder.h>
#include <linux/fs.h>
#include <linux/ratelimit.h>
#include <linux/nls.h>
#ifndef MSDOS_SUPER_MAGIC
#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
#endif
#include "config.h"
#include "compat.h"
#include "version.h"
#include "exfat_raw.h"
#ifndef EXFAT_SUPER_MAGIC
#define EXFAT_SUPER_MAGIC (0x2011BAB0UL)
#endif /* EXFAT_SUPER_MAGIC */
#define EXFAT_SUPER_MAGIC 0x2011BAB0UL
#define EXFAT_ROOT_INO 1
#ifndef EXFAT_SUPER_MAGIC
#define EXFAT_SUPER_MAGIC (0x5EC5DFA4UL)
#endif /* EXFAT_SUPER_MAGIC */
#define EXFAT_SB_DIRTY 0
#define EXFAT_ROOT_INO 1
/* FAT types */
#define FAT12 0x01 // FAT12
#define FAT16 0x0E // Win95 FAT16 (LBA)
#define FAT32 0x0C // Win95 FAT32 (LBA)
#define EXFAT 0x07 // exFAT
/* directory file name */
#define DOS_CUR_DIR_NAME ". "
#define DOS_PAR_DIR_NAME ".. "
#ifdef __LITTLE_ENDIAN
#define UNI_CUR_DIR_NAME ".\0"
#define UNI_PAR_DIR_NAME ".\0.\0"
#else
#define UNI_CUR_DIR_NAME "\0."
#define UNI_PAR_DIR_NAME "\0.\0."
#endif
/* file name lengths */
/* NOTE :
* The maximum length of input or output is limited to 256 including NULL,
* But we allocate 4 extra bytes for utf8 translation reside in last position,
* because utf8 can uses memory upto 6 bytes per one character.
* Therefore, MAX_CHARSET_SIZE supports upto 6 bytes for utf8
*/
#define MAX_UNINAME_BUF_SIZE (((MAX_NAME_LENGTH+1)*2)+4)
#define MAX_DOSNAME_BUF_SIZE ((DOS_NAME_LENGTH+2)+6)
#define MAX_VFSNAME_BUF_SIZE ((MAX_NAME_LENGTH+1)*MAX_CHARSET_SIZE)
#define MAX_CHARSET_SIZE 6 // max size of multi-byte character
#define MAX_NAME_LENGTH 255 // max len of file name excluding NULL
#define DOS_NAME_LENGTH 11 // DOS file name length excluding NULL
#define SECTOR_SIZE_BITS 9 /* VFS sector size is 512 bytes */
#define DENTRY_SIZE 32 /* directory entry size */
#define DENTRY_SIZE_BITS 5
#define MAX_FAT_DENTRIES 65536 /* FAT allows 65536 directory entries */
#define MAX_EXFAT_DENTRIES 8388608 /* exFAT allows 8388608(256MB) directory entries */
/* PBR entries */
#define PBR_SIGNATURE 0xAA55
#define EXT_SIGNATURE 0xAA550000
#define VOL_LABEL "NO NAME " /* size should be 11 */
#define OEM_NAME "MSWIN4.1" /* size should be 8 */
#define STR_FAT12 "FAT12 " /* size should be 8 */
#define STR_FAT16 "FAT16 " /* size should be 8 */
#define STR_FAT32 "FAT32 " /* size should be 8 */
#define STR_EXFAT "EXFAT " /* size should be 8 */
#define VOL_CLEAN 0x0000
#define VOL_DIRTY 0x0002
#define FAT_VOL_DIRTY 0x01
/* max number of clusters */
#define FAT12_THRESHOLD 4087 // 2^12 - 1 + 2 (clu 0 & 1)
#define FAT16_THRESHOLD 65527 // 2^16 - 1 + 2
#define FAT32_THRESHOLD 268435457 // 2^28 - 1 + 2
#define EXFAT_THRESHOLD 268435457 // 2^28 - 1 + 2
/* dentry types */
#define MSDOS_DELETED 0xE5 /* deleted mark */
#define MSDOS_UNUSED 0x00 /* end of directory */
#define EXFAT_UNUSED 0x00 /* end of directory */
#define IS_EXFAT_DELETED(x) ((x) < 0x80) /* deleted file (0x01~0x7F) */
#define EXFAT_INVAL 0x80 /* invalid value */
#define EXFAT_BITMAP 0x81 /* allocation bitmap */
#define EXFAT_UPCASE 0x82 /* upcase table */
#define EXFAT_VOLUME 0x83 /* volume label */
#define EXFAT_FILE 0x85 /* file or dir */
#define EXFAT_STREAM 0xC0 /* stream entry */
#define EXFAT_NAME 0xC1 /* file name entry */
#define EXFAT_ACL 0xC2 /* stream entry */
/* specific flag */
#define MSDOS_LAST_LFN 0x40
/* file attributes */
#define ATTR_NORMAL 0x0000
#define ATTR_READONLY 0x0001
#define ATTR_HIDDEN 0x0002
#define ATTR_SYSTEM 0x0004
#define ATTR_VOLUME 0x0008
#define ATTR_SUBDIR 0x0010
#define ATTR_ARCHIVE 0x0020
#define ATTR_SYMLINK 0x0040
#define ATTR_EXTEND (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | \
ATTR_VOLUME) /* 0x000F */
#define ATTR_EXTEND_MASK (ATTR_EXTEND | ATTR_SUBDIR | ATTR_ARCHIVE)
#define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \
ATTR_SUBDIR | ATTR_ARCHIVE | ATTR_SYMLINK)/* 0x007E */
/* file creation modes */
#define FM_REGULAR 0x00
#define FM_SYMLINK 0x40
/* time modes */
#define TM_CREATE 0
#define TM_MODIFY 1
#define TM_ACCESS 2
/* checksum types */
#define CS_DIR_ENTRY 0
#define CS_PBR_SECTOR 1
#define CS_DEFAULT 2
#define EXFAT_CLUSTERS_UNTRACKED (~0u)
/*
* ioctl command
* exfat error flags
*/
#define EXFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32)
enum exfat_error_mode {
EXFAT_ERRORS_CONT, /* ignore error and continue */
EXFAT_ERRORS_PANIC, /* panic on error */
EXFAT_ERRORS_RO, /* remount r/o on error */
};
/* FAT12/16 BIOS parameter block (64 bytes) */
typedef struct {
__u8 jmp_boot[3];
__u8 oem_name[8];
/*
* exfat nls lossy flag
*/
enum {
NLS_NAME_NO_LOSSY, /* no lossy */
NLS_NAME_LOSSY, /* just detected incorrect filename(s) */
NLS_NAME_OVERLEN, /* the length is over than its limit */
};
__u8 sect_size[2]; /* unaligned */
__u8 sect_per_clus;
__le16 num_reserved; /* . */
__u8 num_fats;
__u8 num_root_entries[2]; /* unaligned */
__u8 num_sectors[2]; /* unaligned */
__u8 media_type;
__le16 num_fat_sectors;
__le16 sectors_in_track;
__le16 num_heads;
__le32 num_hid_sectors; /* . */
__le32 num_huge_sectors;
#define EXFAT_HASH_BITS 8
#define EXFAT_HASH_SIZE (1UL << EXFAT_HASH_BITS)
__u8 phy_drv_no;
__u8 state; /* used by WindowsNT for mount state */
__u8 ext_signature;
__u8 vol_serial[4];
__u8 vol_label[11];
__u8 vol_type[8];
__le16 dummy;
} bpb16_t;
/*
* Type Definitions
*/
#define ES_2_ENTRIES 2
#define ES_ALL_ENTRIES 0
/* FAT32 BIOS parameter block (64 bytes) */
typedef struct {
__u8 jmp_boot[3];
__u8 oem_name[8];
#define DIR_DELETED 0xFFFF0321
__u8 sect_size[2]; /* unaligned */
__u8 sect_per_clus;
__le16 num_reserved;
__u8 num_fats;
__u8 num_root_entries[2]; /* unaligned */
__u8 num_sectors[2]; /* unaligned */
__u8 media_type;
__le16 num_fat_sectors; /* zero */
__le16 sectors_in_track;
__le16 num_heads;
__le32 num_hid_sectors; /* . */
__le32 num_huge_sectors;
/* type values */
#define TYPE_UNUSED 0x0000
#define TYPE_DELETED 0x0001
#define TYPE_INVALID 0x0002
#define TYPE_CRITICAL_PRI 0x0100
#define TYPE_BITMAP 0x0101
#define TYPE_UPCASE 0x0102
#define TYPE_VOLUME 0x0103
#define TYPE_DIR 0x0104
#define TYPE_FILE 0x011F
#define TYPE_CRITICAL_SEC 0x0200
#define TYPE_STREAM 0x0201
#define TYPE_EXTEND 0x0202
#define TYPE_ACL 0x0203
#define TYPE_BENIGN_PRI 0x0400
#define TYPE_GUID 0x0401
#define TYPE_PADDING 0x0402
#define TYPE_ACLTAB 0x0403
#define TYPE_BENIGN_SEC 0x0800
#define TYPE_ALL 0x0FFF
__le32 num_fat32_sectors;
__le16 ext_flags;
__u8 fs_version[2];
__le32 root_cluster; /* . */
__le16 fsinfo_sector;
__le16 backup_sector;
__le16 reserved[6]; /* . */
} bpb32_t;
#define MAX_CHARSET_SIZE 6 /* max size of multi-byte character */
#define MAX_NAME_LENGTH 255 /* max len of file name excluding NULL */
#define MAX_VFSNAME_BUF_SIZE ((MAX_NAME_LENGTH + 1) * MAX_CHARSET_SIZE)
/* FAT32 EXTEND BIOS parameter block (32 bytes) */
typedef struct {
__u8 phy_drv_no;
__u8 state; /* used by WindowsNT for mount state */
__u8 ext_signature;
__u8 vol_serial[4];
__u8 vol_label[11];
__u8 vol_type[8];
__le16 dummy[3];
} bsx32_t;
/* Enough size to hold 256 dentry (even 512 Byte sector) */
#define DIR_CACHE_SIZE (256*sizeof(struct exfat_dentry)/512+1)
/* EXFAT BIOS parameter block (64 bytes) */
typedef struct {
__u8 jmp_boot[3];
__u8 oem_name[8];
__u8 res_zero[53];
} bpb64_t;
#define EXFAT_HINT_NONE -1
#define EXFAT_MIN_SUBDIR 2
/* EXFAT EXTEND BIOS parameter block (56 bytes) */
typedef struct {
__le64 vol_offset;
__le64 vol_length;
__le32 fat_offset;
__le32 fat_length;
__le32 clu_offset;
__le32 clu_count;
__le32 root_cluster;
__le32 vol_serial;
__u8 fs_version[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];
} bsx64_t;
/*
* helpers for cluster size to byte conversion.
*/
#define EXFAT_CLU_TO_B(b, sbi) ((b) << (sbi)->cluster_size_bits)
#define EXFAT_B_TO_CLU(b, sbi) ((b) >> (sbi)->cluster_size_bits)
#define EXFAT_B_TO_CLU_ROUND_UP(b, sbi) \
(((b - 1) >> (sbi)->cluster_size_bits) + 1)
#define EXFAT_CLU_OFFSET(off, sbi) ((off) & ((sbi)->cluster_size - 1))
/* FAT32 PBR (64 bytes) */
typedef struct {
bpb16_t bpb;
} pbr16_t;
/*
* helpers for block size to byte conversion.
*/
#define EXFAT_BLK_TO_B(b, sb) ((b) << (sb)->s_blocksize_bits)
#define EXFAT_B_TO_BLK(b, sb) ((b) >> (sb)->s_blocksize_bits)
#define EXFAT_B_TO_BLK_ROUND_UP(b, sb) \
(((b - 1) >> (sb)->s_blocksize_bits) + 1)
#define EXFAT_BLK_OFFSET(off, sb) ((off) & ((sb)->s_blocksize - 1))
/* FAT32 PBR[BPB+BSX] (96 bytes) */
typedef struct {
bpb32_t bpb;
bsx32_t bsx;
} pbr32_t;
/*
* helpers for block size to dentry size conversion.
*/
#define EXFAT_B_TO_DEN_IDX(b, sbi) \
((b) << ((sbi)->cluster_size_bits - DENTRY_SIZE_BITS))
#define EXFAT_B_TO_DEN(b) ((b) >> DENTRY_SIZE_BITS)
#define EXFAT_DEN_TO_B(b) ((b) << DENTRY_SIZE_BITS)
/* EXFAT PBR[BPB+BSX] (120 bytes) */
typedef struct {
bpb64_t bpb;
bsx64_t bsx;
} pbr64_t;
/*
* helpers for fat entry.
*/
#define FAT_ENT_SIZE (4)
#define FAT_ENT_SIZE_BITS (2)
#define FAT_ENT_OFFSET_SECTOR(sb, loc) (EXFAT_SB(sb)->FAT1_start_sector + \
(((u64)loc << FAT_ENT_SIZE_BITS) >> sb->s_blocksize_bits))
#define FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc) \
((loc << FAT_ENT_SIZE_BITS) & (sb->s_blocksize - 1))
/* Common PBR[Partition Boot Record] (512 bytes) */
typedef struct {
/*
* helpers for bitmap.
*/
#define CLUSTER_TO_BITMAP_ENT(clu) ((clu) - EXFAT_RESERVED_CLUSTERS)
#define BITMAP_ENT_TO_CLUSTER(ent) ((ent) + EXFAT_RESERVED_CLUSTERS)
#define BITS_PER_SECTOR(sb) ((sb)->s_blocksize * BITS_PER_BYTE)
#define BITS_PER_SECTOR_MASK(sb) (BITS_PER_SECTOR(sb) - 1)
#define BITMAP_OFFSET_SECTOR_INDEX(sb, ent) \
((ent / BITS_PER_BYTE) >> (sb)->s_blocksize_bits)
#define BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent) (ent & BITS_PER_SECTOR_MASK(sb))
#define BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent) \
((ent / BITS_PER_BYTE) & ((sb)->s_blocksize - 1))
#define BITS_PER_BYTE_MASK 0x7
#define IGNORED_BITS_REMAINED(clu, clu_base) ((1 << ((clu) - (clu_base))) - 1)
struct exfat_dentry_namebuf {
char *lfn;
int lfnbuf_len; /* usally MAX_UNINAME_BUF_SIZE */
};
/* unicode name structure */
struct exfat_uni_name {
/* +3 for null and for converting */
unsigned short name[MAX_NAME_LENGTH + 3];
u16 name_hash;
unsigned char name_len;
};
/* directory structure */
struct exfat_chain {
unsigned int dir;
unsigned int size;
unsigned char flags;
};
/* first empty entry hint information */
struct exfat_hint_femp {
/* entry index of a directory */
int eidx;
/* count of continuous empty entry */
int count;
/* the cluster that first empty slot exists in */
struct exfat_chain cur;
};
/* hint structure */
struct exfat_hint {
unsigned int clu;
union {
__u8 raw[64];
bpb16_t f16;
bpb32_t f32;
bpb64_t f64;
} bpb;
union {
__u8 raw[56];
bsx32_t f32;
bsx64_t f64;
} bsx;
__u8 boot_code[390];
__le16 signature;
} pbr_t;
unsigned int off; /* cluster offset */
int eidx; /* entry index */
};
};
/* FAT32 filesystem information sector (512 bytes) */
typedef struct {
__le32 signature1; // aligned
__u8 reserved1[480];
__le32 signature2; // aligned
__le32 free_cluster; // aligned
__le32 next_cluster; // aligned
__u8 reserved2[14];
__le16 signature3[2];
} fat32_fsi_t;
struct exfat_entry_set_cache {
struct super_block *sb;
bool modified;
unsigned int start_off;
int num_bh;
struct buffer_head *bh[DIR_CACHE_SIZE];
unsigned int num_entries;
};
/* FAT directory entry (32 bytes) */
typedef struct {
__u8 dummy[32];
} DENTRY_T;
struct exfat_dir_entry {
struct exfat_chain dir;
int entry;
unsigned int type;
unsigned int start_clu;
unsigned char flags;
unsigned short attr;
loff_t size;
unsigned int num_subdirs;
struct timespec64 atime;
struct timespec64 mtime;
struct timespec64 crtime;
struct exfat_dentry_namebuf namebuf;
};
typedef struct {
__u8 name[DOS_NAME_LENGTH]; /* 11 chars */
__u8 attr;
__u8 lcase;
__u8 create_time_ms;
__le16 create_time; // aligned
__le16 create_date; // aligned
__le16 access_date; // aligned
__le16 start_clu_hi; // aligned
__le16 modify_time; // aligned
__le16 modify_date; // aligned
__le16 start_clu_lo; // aligned
__le32 size; // aligned
} DOS_DENTRY_T;
/*
* exfat mount in-memory data
*/
struct exfat_mount_options {
kuid_t fs_uid;
kgid_t fs_gid;
unsigned short fs_fmask;
unsigned short fs_dmask;
/* permission for setting the [am]time */
unsigned short allow_utime;
/* charset for filename input/display */
char *iocharset;
/* fake return success on setattr(e.g. chmods/chowns) */
unsigned char quiet;
/* on error: continue, panic, remount-ro */
enum exfat_error_mode errors;
unsigned utf8:1, /* Use of UTF-8 character set */
discard:1; /* Issue discard requests on deletions */
int time_offset; /* Offset of timestamps from UTC (in minutes) */
};
/* FAT extended directory entry (32 bytes) */
typedef struct {
__u8 order;
__u8 unicode_0_4[10];
__u8 attr;
__u8 sysid;
__u8 checksum;
__le16 unicode_5_10[6]; // aligned
__le16 start_clu; // aligned
__le16 unicode_11_12[2]; // aligned
} EXT_DENTRY_T;
/*
* EXFAT file system superblock in-memory data
*/
struct exfat_sb_info {
unsigned long long num_sectors; /* num of sectors in volume */
unsigned int num_clusters; /* num of clusters in volume */
unsigned int cluster_size; /* cluster size in bytes */
unsigned int cluster_size_bits;
unsigned int sect_per_clus; /* cluster size in sectors */
unsigned int sect_per_clus_bits;
unsigned long long FAT1_start_sector; /* FAT1 start sector */
unsigned long long FAT2_start_sector; /* FAT2 start sector */
unsigned long long data_start_sector; /* data area start sector */
unsigned int num_FAT_sectors; /* num of FAT sectors */
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 *boot_bh; /* buffer_head of BOOT sector */
/* EXFAT file directory entry (32 bytes) */
typedef struct {
__u8 type;
__u8 num_ext;
__le16 checksum; // aligned
__le16 attr; // aligned
__le16 reserved1;
__le16 create_time; // aligned
__le16 create_date; // aligned
__le16 modify_time; // aligned
__le16 modify_date; // aligned
__le16 access_time; // aligned
__le16 access_date; // aligned
__u8 create_time_ms;
__u8 modify_time_ms;
__u8 access_time_ms;
__u8 reserved2[9];
} FILE_DENTRY_T;
unsigned int map_clu; /* allocation bitmap start cluster */
unsigned int map_sectors; /* num of allocation bitmap sectors */
struct buffer_head **vol_amap; /* allocation bitmap */
/* EXFAT stream extension directory entry (32 bytes) */
typedef struct {
__u8 type;
__u8 flags;
__u8 reserved1;
__u8 name_len;
__le16 name_hash; // aligned
__le16 reserved2;
__le64 valid_size; // aligned
__le32 reserved3; // aligned
__le32 start_clu; // aligned
__le64 size; // aligned
} STRM_DENTRY_T;
unsigned short *vol_utbl; /* upcase table */
/* EXFAT file name directory entry (32 bytes) */
typedef struct {
__u8 type;
__u8 flags;
__le16 unicode_0_14[15]; // aligned
} NAME_DENTRY_T;
unsigned int clu_srch_ptr; /* cluster search pointer */
unsigned int used_clusters; /* number of used clusters */
/* EXFAT allocation bitmap directory entry (32 bytes) */
typedef struct {
__u8 type;
__u8 flags;
__u8 reserved[18];
__le32 start_clu; // aligned
__le64 size; // aligned
} BMAP_DENTRY_T;
unsigned long s_state;
struct mutex s_lock; /* superblock lock */
struct exfat_mount_options options;
struct nls_table *nls_io; /* Charset used for input and display */
struct ratelimit_state ratelimit;
/* EXFAT up-case table directory entry (32 bytes) */
typedef struct {
__u8 type;
__u8 reserved1[3];
__le32 checksum; // aligned
__u8 reserved2[12];
__le32 start_clu; // aligned
__le64 size; // aligned
} CASE_DENTRY_T;
spinlock_t inode_hash_lock;
struct hlist_head inode_hashtable[EXFAT_HASH_SIZE];
/* EXFAT volume label directory entry (32 bytes) */
typedef struct {
__u8 type;
__u8 label_len;
__le16 unicode_0_10[11]; // aligned
__u8 reserved[8];
} VOLM_DENTRY_T;
struct rcu_head rcu;
};
#endif /* _EXFAT_FS_H */
/*
* EXFAT file system inode in-memory data
*/
struct exfat_inode_info {
struct exfat_chain dir;
int entry;
unsigned int type;
unsigned short attr;
unsigned int start_clu;
unsigned char flags;
/*
* the copy of low 32bit of i_version to check
* the validation of hint_stat.
*/
unsigned int version;
/* file offset or dentry index for readdir */
loff_t rwoffset;
/* hint for cluster last accessed */
struct exfat_hint hint_bmap;
/* hint for entry index we try to lookup next time */
struct exfat_hint hint_stat;
/* hint for first empty entry */
struct exfat_hint_femp hint_femp;
spinlock_t cache_lru_lock;
struct list_head cache_lru;
int nr_caches;
/* for avoiding the race between alloc and free */
unsigned int cache_valid_id;
/*
* NOTE: i_size_ondisk is 64bits, so must hold ->inode_lock to access.
* physically allocated size.
*/
loff_t i_size_ondisk;
/* block-aligned i_size (used in cont_write_begin) */
loff_t i_size_aligned;
/* on-disk position of directory entry or 0 */
loff_t i_pos;
/* hash by i_location */
struct hlist_node i_hash_fat;
/* protect bmap against truncate */
struct rw_semaphore truncate_lock;
struct inode vfs_inode;
/* File creation time */
struct timespec64 i_crtime;
};
static inline struct exfat_sb_info *EXFAT_SB(struct super_block *sb)
{
return sb->s_fs_info;
}
static inline struct exfat_inode_info *EXFAT_I(struct inode *inode)
{
return container_of(inode, struct exfat_inode_info, vfs_inode);
}
/*
* If ->i_mode can't hold 0222 (i.e. ATTR_RO), we use ->i_attrs to
* save ATTR_RO instead of ->i_mode.
*
* If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only
* bit, it's just used as flag for app.
*/
static inline int exfat_mode_can_hold_ro(struct inode *inode)
{
struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
if (S_ISDIR(inode->i_mode))
return 0;
if ((~sbi->options.fs_fmask) & 0222)
return 1;
return 0;
}
/* Convert attribute bits and a mask to the UNIX mode. */
static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi,
unsigned short attr, mode_t mode)
{
if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR))
mode &= ~0222;
if (attr & ATTR_SUBDIR)
return (mode & ~sbi->options.fs_dmask) | S_IFDIR;
return (mode & ~sbi->options.fs_fmask) | S_IFREG;
}
/* Return the FAT attribute byte for this inode */
static inline unsigned short exfat_make_attr(struct inode *inode)
{
unsigned short attr = EXFAT_I(inode)->attr;
if (S_ISDIR(inode->i_mode))
attr |= ATTR_SUBDIR;
if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222))
attr |= ATTR_READONLY;
return attr;
}
static inline void exfat_save_attr(struct inode *inode, unsigned short attr)
{
if (exfat_mode_can_hold_ro(inode))
EXFAT_I(inode)->attr = attr & (ATTR_RWMASK | ATTR_READONLY);
else
EXFAT_I(inode)->attr = attr & ATTR_RWMASK;
}
static inline bool exfat_is_last_sector_in_cluster(struct exfat_sb_info *sbi,
sector_t sec)
{
return ((sec - sbi->data_start_sector + 1) &
((1 << sbi->sect_per_clus_bits) - 1)) == 0;
}
static inline sector_t exfat_cluster_to_sector(struct exfat_sb_info *sbi,
unsigned int clus)
{
return ((clus - EXFAT_RESERVED_CLUSTERS) << sbi->sect_per_clus_bits) +
sbi->data_start_sector;
}
static inline int exfat_sector_to_cluster(struct exfat_sb_info *sbi,
sector_t sec)
{
return ((sec - sbi->data_start_sector) >> sbi->sect_per_clus_bits) +
EXFAT_RESERVED_CLUSTERS;
}
/* super.c */
int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag);
/* fatent.c */
#define exfat_get_next_cluster(sb, pclu) exfat_ent_get(sb, *(pclu), pclu)
int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
struct exfat_chain *p_chain);
int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain);
int exfat_ent_get(struct super_block *sb, unsigned int loc,
unsigned int *content);
int exfat_ent_set(struct super_block *sb, unsigned int loc,
unsigned int content);
int exfat_count_ext_entries(struct super_block *sb, struct exfat_chain *p_dir,
int entry, struct exfat_dentry *p_entry);
int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain,
unsigned int len);
int exfat_zeroed_cluster(struct inode *dir, unsigned int clu);
int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain,
unsigned int *ret_clu);
int exfat_count_num_clusters(struct super_block *sb,
struct exfat_chain *p_chain, unsigned int *ret_count);
/* balloc.c */
int exfat_load_bitmap(struct super_block *sb);
void exfat_free_bitmap(struct exfat_sb_info *sbi);
int exfat_set_bitmap(struct inode *inode, unsigned int clu);
void exfat_clear_bitmap(struct inode *inode, unsigned int clu);
unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu);
int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count);
/* file.c */
extern const struct file_operations exfat_file_operations;
int __exfat_truncate(struct inode *inode, loff_t new_size);
void exfat_truncate(struct inode *inode, loff_t size);
int exfat_setattr(struct dentry *dentry, struct iattr *attr);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
int exfat_getattr(const struct path *path, struct kstat *stat,
unsigned int request_mask, unsigned int query_flags);
#else
int exfat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
#endif
int exfat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync);
/* namei.c */
extern const struct dentry_operations exfat_dentry_ops;
extern const struct dentry_operations exfat_utf8_dentry_ops;
/* cache.c */
int exfat_cache_init(void);
void exfat_cache_shutdown(void);
void exfat_cache_init_inode(struct inode *inode);
void exfat_cache_inval_inode(struct inode *inode);
int exfat_get_cluster(struct inode *inode, unsigned int cluster,
unsigned int *fclus, unsigned int *dclus,
unsigned int *last_dclus, int allow_eof);
/* dir.c */
extern const struct inode_operations exfat_dir_inode_operations;
extern const struct file_operations exfat_dir_operations;
unsigned int exfat_get_entry_type(struct exfat_dentry *p_entry);
int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir,
int entry, unsigned int type, unsigned int start_clu,
unsigned long long size);
int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir,
int entry, int num_entries, struct exfat_uni_name *p_uniname);
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);
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,
int num_entries, unsigned int type);
int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu);
int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir,
int entry, sector_t *sector, int *offset);
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);
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 */
extern const struct inode_operations exfat_file_inode_operations;
void exfat_sync_inode(struct inode *inode);
struct inode *exfat_build_inode(struct super_block *sb,
struct exfat_dir_entry *info, loff_t i_pos);
void exfat_hash_inode(struct inode *inode, loff_t i_pos);
void exfat_unhash_inode(struct inode *inode);
struct inode *exfat_iget(struct super_block *sb, loff_t i_pos);
int exfat_write_inode(struct inode *inode, struct writeback_control *wbc);
void exfat_evict_inode(struct inode *inode);
int exfat_block_truncate_page(struct inode *inode, loff_t from);
/* xattr.c */
#ifdef CONFIG_EXFAT_VIRTUAL_XATTR
extern int exfat_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags);
extern ssize_t exfat_getxattr(struct dentry *dentry, const char *name, void *value, size_t size);
extern ssize_t exfat_listxattr(struct dentry *dentry, char *list, size_t size);
extern int exfat_removexattr(struct dentry *dentry, const char *name);
extern const struct xattr_handler *exfat_xattr_handlers[];
#else
#define exfat_xattr_handlers NULL
#endif
/* exfat/nls.c */
unsigned short exfat_toupper(struct super_block *sb, unsigned short a);
int exfat_uniname_ncmp(struct super_block *sb, unsigned short *a,
unsigned short *b, unsigned int len);
int exfat_utf16_to_nls(struct super_block *sb,
struct exfat_uni_name *uniname, unsigned char *p_cstring,
int len);
int exfat_nls_to_utf16(struct super_block *sb,
const unsigned char *p_cstring, const int len,
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);
/* exfat/misc.c */
void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
__printf(3, 4) __cold;
#define exfat_fs_error(sb, fmt, args...) \
__exfat_fs_error(sb, 1, fmt, ## args)
#define exfat_fs_error_ratelimit(sb, fmt, args...) \
__exfat_fs_error(sb, __ratelimit(&EXFAT_SB(sb)->ratelimit), \
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_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_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);
void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec);
#endif /* !_EXFAT_FS_H */

165
fs/exfat/exfat_raw.h Normal file
View File

@ -0,0 +1,165 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#ifndef _EXFAT_RAW_H
#define _EXFAT_RAW_H
#include <linux/types.h>
#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
#define EXFAT_FREE_CLUSTER 0
/* Cluster 0, 1 are reserved, the first cluster is 2 in the cluster heap. */
#define EXFAT_RESERVED_CLUSTERS 2
#define EXFAT_FIRST_CLUSTER 2
#define EXFAT_DATA_CLUSTER_COUNT(sbi) \
((sbi)->num_clusters - EXFAT_RESERVED_CLUSTERS)
/* AllocationPossible and NoFatChain field in GeneralSecondaryFlags Field */
#define ALLOC_FAT_CHAIN 0x01
#define ALLOC_NO_FAT_CHAIN 0x03
#define DENTRY_SIZE 32 /* directory entry size */
#define DENTRY_SIZE_BITS 5
/* exFAT allows 8388608(256MB) directory entries */
#define MAX_EXFAT_DENTRIES 8388608
/* dentry types */
#define EXFAT_UNUSED 0x00 /* end of directory */
#define EXFAT_DELETE (~0x80)
#define IS_EXFAT_DELETED(x) ((x) < 0x80) /* deleted file (0x01~0x7F) */
#define EXFAT_INVAL 0x80 /* invalid value */
#define EXFAT_BITMAP 0x81 /* allocation bitmap */
#define EXFAT_UPCASE 0x82 /* upcase table */
#define EXFAT_VOLUME 0x83 /* volume label */
#define EXFAT_FILE 0x85 /* file or dir */
#define EXFAT_GUID 0xA0
#define EXFAT_PADDING 0xA1
#define EXFAT_ACLTAB 0xA2
#define EXFAT_STREAM 0xC0 /* stream entry */
#define EXFAT_NAME 0xC1 /* file name entry */
#define EXFAT_ACL 0xC2 /* stream entry */
#define IS_EXFAT_CRITICAL_PRI(x) (x < 0xA0)
#define IS_EXFAT_BENIGN_PRI(x) (x < 0xC0)
#define IS_EXFAT_CRITICAL_SEC(x) (x < 0xE0)
/* checksum types */
#define CS_DIR_ENTRY 0
#define CS_BOOT_SECTOR 1
#define CS_DEFAULT 2
/* file attributes */
#define ATTR_READONLY 0x0001
#define ATTR_HIDDEN 0x0002
#define ATTR_SYSTEM 0x0004
#define ATTR_VOLUME 0x0008
#define ATTR_SUBDIR 0x0010
#define ATTR_ARCHIVE 0x0020
#define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \
ATTR_SUBDIR | ATTR_ARCHIVE)
#define BOOTSEC_JUMP_BOOT_LEN 3
#define BOOTSEC_FS_NAME_LEN 8
#define BOOTSEC_OLDBPB_LEN 53
#define EXFAT_FILE_NAME_LEN 15
/* 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;
__le32 clu_offset;
__le32 clu_count;
__le32 root_cluster;
__le32 vol_serial;
__u8 fs_revision[2];
__le16 vol_flags;
__u8 sect_size_bits;
__u8 sect_per_clus_bits;
__u8 num_fats;
__u8 drv_sel;
__u8 percent_in_use;
__u8 reserved[7];
__u8 boot_code[390];
__le16 signature;
} __packed;
struct exfat_dentry {
__u8 type;
union {
struct {
__u8 num_ext;
__le16 checksum;
__le16 attr;
__le16 reserved1;
__le16 create_time;
__le16 create_date;
__le16 modify_time;
__le16 modify_date;
__le16 access_time;
__le16 access_date;
__u8 create_time_cs;
__u8 modify_time_cs;
__u8 create_tz;
__u8 modify_tz;
__u8 access_tz;
__u8 reserved2[7];
} __packed file; /* file directory entry */
struct {
__u8 flags;
__u8 reserved1;
__u8 name_len;
__le16 name_hash;
__le16 reserved2;
__le64 valid_size;
__le32 reserved3;
__le32 start_clu;
__le64 size;
} __packed stream; /* stream extension directory entry */
struct {
__u8 flags;
__le16 unicode_0_14[EXFAT_FILE_NAME_LEN];
} __packed name; /* file name directory entry */
struct {
__u8 flags;
__u8 reserved[18];
__le32 start_clu;
__le64 size;
} __packed bitmap; /* allocation bitmap directory entry */
struct {
__u8 reserved1[3];
__le32 checksum;
__u8 reserved2[12];
__le32 start_clu;
__le64 size;
} __packed upcase; /* up-case table directory entry */
} __packed dentry;
} __packed;
#define EXFAT_TZ_VALID (1 << 7)
/* Jan 1 GMT 00:00:00 1980 */
#define EXFAT_MIN_TIMESTAMP_SECS 315532800LL
/* Dec 31 GMT 23:59:59 2107 */
#define EXFAT_MAX_TIMESTAMP_SECS 4354819199LL
#endif /* !_EXFAT_RAW_H */

View File

@ -1,329 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*
* extent.c: Improve the performance of traversing fat chain
*/
/*
* linux/fs/fat/cache.c
*
* Written 1992,1993 by Werner Almesberger
*
* Mar 1999. AV. Changed cache, so that it uses the starting cluster instead
* of inode number.
* May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers.
*/
#include <linux/slab.h>
#include "exfat.h"
#include "core.h"
#define EXTENT_CACHE_VALID 0
/* this must be > 0. */
#define EXTENT_MAX_CACHE 16
struct extent_cache {
struct list_head cache_list;
u32 nr_contig; /* number of contiguous clusters */
u32 fcluster; /* cluster number in the file. */
u32 dcluster; /* cluster number on disk. */
};
struct extent_cache_id {
u32 id;
u32 nr_contig;
u32 fcluster;
u32 dcluster;
};
static struct kmem_cache *extent_cache_cachep;
static void init_once(void *c)
{
struct extent_cache *cache = (struct extent_cache *)c;
INIT_LIST_HEAD(&cache->cache_list);
}
s32 exfat_extent_cache_init(void)
{
extent_cache_cachep = kmem_cache_create("exfat_extent_cache",
sizeof(struct extent_cache),
0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
init_once);
if (!extent_cache_cachep)
return -ENOMEM;
return 0;
}
void exfat_extent_cache_shutdown(void)
{
if (!extent_cache_cachep)
return;
kmem_cache_destroy(extent_cache_cachep);
}
void exfat_extent_cache_init_inode(struct inode *inode)
{
EXTENT_T *extent = &(EXFAT_I(inode)->fid.extent);
spin_lock_init(&extent->cache_lru_lock);
extent->nr_caches = 0;
extent->cache_valid_id = EXTENT_CACHE_VALID + 1;
INIT_LIST_HEAD(&extent->cache_lru);
}
static inline struct extent_cache *extent_cache_alloc(void)
{
return kmem_cache_alloc(extent_cache_cachep, GFP_NOFS);
}
static inline void extent_cache_free(struct extent_cache *cache)
{
BUG_ON(!list_empty(&cache->cache_list));
kmem_cache_free(extent_cache_cachep, cache);
}
static inline void extent_cache_update_lru(struct inode *inode,
struct extent_cache *cache)
{
EXTENT_T *extent = &(EXFAT_I(inode)->fid.extent);
if (extent->cache_lru.next != &cache->cache_list)
list_move(&cache->cache_list, &extent->cache_lru);
}
static u32 extent_cache_lookup(struct inode *inode, u32 fclus,
struct extent_cache_id *cid,
u32 *cached_fclus, u32 *cached_dclus)
{
EXTENT_T *extent = &(EXFAT_I(inode)->fid.extent);
static struct extent_cache nohit = { .fcluster = 0, };
struct extent_cache *hit = &nohit, *p;
u32 offset = CLUS_EOF;
spin_lock(&extent->cache_lru_lock);
list_for_each_entry(p, &extent->cache_lru, cache_list) {
/* Find the cache of "fclus" or nearest cache. */
if (p->fcluster <= fclus && hit->fcluster < p->fcluster) {
hit = p;
if ((hit->fcluster + hit->nr_contig) < fclus) {
offset = hit->nr_contig;
} else {
offset = fclus - hit->fcluster;
break;
}
}
}
if (hit != &nohit) {
extent_cache_update_lru(inode, hit);
cid->id = extent->cache_valid_id;
cid->nr_contig = hit->nr_contig;
cid->fcluster = hit->fcluster;
cid->dcluster = hit->dcluster;
*cached_fclus = cid->fcluster + offset;
*cached_dclus = cid->dcluster + offset;
}
spin_unlock(&extent->cache_lru_lock);
return offset;
}
static struct extent_cache *extent_cache_merge(struct inode *inode,
struct extent_cache_id *new)
{
EXTENT_T *extent = &(EXFAT_I(inode)->fid.extent);
struct extent_cache *p;
list_for_each_entry(p, &extent->cache_lru, cache_list) {
/* Find the same part as "new" in cluster-chain. */
if (p->fcluster == new->fcluster) {
ASSERT(p->dcluster == new->dcluster);
if (new->nr_contig > p->nr_contig)
p->nr_contig = new->nr_contig;
return p;
}
}
return NULL;
}
static void extent_cache_add(struct inode *inode, struct extent_cache_id *new)
{
EXTENT_T *extent = &(EXFAT_I(inode)->fid.extent);
struct extent_cache *cache, *tmp;
if (new->fcluster == -1) /* dummy cache */
return;
spin_lock(&extent->cache_lru_lock);
if (new->id != EXTENT_CACHE_VALID &&
new->id != extent->cache_valid_id)
goto out; /* this cache was invalidated */
cache = extent_cache_merge(inode, new);
if (cache == NULL) {
if (extent->nr_caches < EXTENT_MAX_CACHE) {
extent->nr_caches++;
spin_unlock(&extent->cache_lru_lock);
tmp = extent_cache_alloc();
if (!tmp) {
spin_lock(&extent->cache_lru_lock);
extent->nr_caches--;
spin_unlock(&extent->cache_lru_lock);
return;
}
spin_lock(&extent->cache_lru_lock);
cache = extent_cache_merge(inode, new);
if (cache != NULL) {
extent->nr_caches--;
extent_cache_free(tmp);
goto out_update_lru;
}
cache = tmp;
} else {
struct list_head *p = extent->cache_lru.prev;
cache = list_entry(p, struct extent_cache, cache_list);
}
cache->fcluster = new->fcluster;
cache->dcluster = new->dcluster;
cache->nr_contig = new->nr_contig;
}
out_update_lru:
extent_cache_update_lru(inode, cache);
out:
spin_unlock(&extent->cache_lru_lock);
}
/*
* Cache invalidation occurs rarely, thus the LRU chain is not updated. It
* fixes itself after a while.
*/
static void __exfat_extent_cache_inval_inode(struct inode *inode)
{
EXTENT_T *extent = &(EXFAT_I(inode)->fid.extent);
struct extent_cache *cache;
while (!list_empty(&extent->cache_lru)) {
cache = list_entry(extent->cache_lru.next,
struct extent_cache, cache_list);
list_del_init(&cache->cache_list);
extent->nr_caches--;
extent_cache_free(cache);
}
/* Update. The copy of caches before this id is discarded. */
extent->cache_valid_id++;
if (extent->cache_valid_id == EXTENT_CACHE_VALID)
extent->cache_valid_id++;
}
void exfat_extent_cache_inval_inode(struct inode *inode)
{
EXTENT_T *extent = &(EXFAT_I(inode)->fid.extent);
spin_lock(&extent->cache_lru_lock);
__exfat_extent_cache_inval_inode(inode);
spin_unlock(&extent->cache_lru_lock);
}
static inline s32 cache_contiguous(struct extent_cache_id *cid, u32 dclus)
{
cid->nr_contig++;
return ((cid->dcluster + cid->nr_contig) == dclus);
}
static inline void cache_init(struct extent_cache_id *cid, u32 fclus, u32 dclus)
{
cid->id = EXTENT_CACHE_VALID;
cid->fcluster = fclus;
cid->dcluster = dclus;
cid->nr_contig = 0;
}
s32 exfat_extent_get_clus(struct inode *inode, u32 cluster, u32 *fclus,
u32 *dclus, u32 *last_dclus, s32 allow_eof)
{
struct super_block *sb = inode->i_sb;
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
u32 limit = fsi->num_clusters;
FILE_ID_T *fid = &(EXFAT_I(inode)->fid);
struct extent_cache_id cid;
u32 content;
/* FOR GRACEFUL ERROR HANDLING */
if (IS_CLUS_FREE(fid->start_clu)) {
exfat_fs_error(sb, "invalid access to "
"extent cache (entry 0x%08x)", fid->start_clu);
ASSERT(0);
return -EIO;
}
*fclus = 0;
*dclus = fid->start_clu;
*last_dclus = *dclus;
/*
* Don`t use extent_cache if zero offset or non-cluster allocation
*/
if ((cluster == 0) || IS_CLUS_EOF(*dclus))
return 0;
cache_init(&cid, CLUS_EOF, CLUS_EOF);
if (extent_cache_lookup(inode, cluster, &cid, fclus, dclus) == CLUS_EOF) {
/*
* dummy, always not contiguous
* This is reinitialized by cache_init(), later.
*/
ASSERT((cid.id == EXTENT_CACHE_VALID)
&& (cid.fcluster == CLUS_EOF)
&& (cid.dcluster == CLUS_EOF)
&& (cid.nr_contig == 0));
}
if (*fclus == cluster)
return 0;
while (*fclus < cluster) {
/* prevent the infinite loop of cluster chain */
if (*fclus > limit) {
exfat_fs_error(sb,
"%s: detected the cluster chain loop"
" (i_pos %u)", __func__,
(*fclus));
return -EIO;
}
if (exfat_ent_get_safe(sb, *dclus, &content))
return -EIO;
*last_dclus = *dclus;
*dclus = content;
(*fclus)++;
if (IS_CLUS_EOF(content)) {
if (!allow_eof) {
exfat_fs_error(sb,
"%s: invalid cluster chain (i_pos %u,"
"last_clus 0x%08x is EOF)",
__func__, *fclus, (*last_dclus));
return -EIO;
}
break;
}
if (!cache_contiguous(&cid, *dclus))
cache_init(&cid, *fclus, *dclus);
}
extent_cache_add(inode, &cid);
return 0;
}

View File

@ -1,113 +1,459 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*
* fatent.c: exFAT FAT entry manager
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#include <linux/slab.h>
#include <asm/unaligned.h>
#include <linux/buffer_head.h>
#include "exfat.h"
#include "core.h"
#include "exfat_fs.h"
/* All buffer structures are protected w/ fsi->v_sem */
static inline bool is_reserved_clus(u32 clus)
static int exfat_mirror_bh(struct super_block *sb, sector_t sec,
struct buffer_head *bh)
{
if (IS_CLUS_FREE(clus))
return true;
if (IS_CLUS_EOF(clus))
return true;
if (IS_CLUS_BAD(clus))
return true;
return false;
struct buffer_head *c_bh;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
sector_t sec2;
int err = 0;
if (sbi->FAT2_start_sector != sbi->FAT1_start_sector) {
sec2 = sec - sbi->FAT1_start_sector + sbi->FAT2_start_sector;
c_bh = sb_getblk(sb, sec2);
if (!c_bh)
return -ENOMEM;
memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize);
set_buffer_uptodate(c_bh);
mark_buffer_dirty(c_bh);
if (sb->s_flags & SB_SYNCHRONOUS)
err = sync_dirty_buffer(c_bh);
brelse(c_bh);
}
return err;
}
static inline bool is_valid_clus(FS_INFO_T *fsi, u32 clus)
static int __exfat_ent_get(struct super_block *sb, unsigned int loc,
unsigned int *content)
{
if (clus < CLUS_BASE || fsi->num_clusters <= clus)
unsigned int off;
sector_t sec;
struct buffer_head *bh;
sec = FAT_ENT_OFFSET_SECTOR(sb, loc);
off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc);
bh = sb_bread(sb, sec);
if (!bh)
return -EIO;
*content = le32_to_cpu(*(__le32 *)(&bh->b_data[off]));
/* remap reserved clusters to simplify code */
if (*content > EXFAT_BAD_CLUSTER)
*content = EXFAT_EOF_CLUSTER;
brelse(bh);
return 0;
}
int exfat_ent_set(struct super_block *sb, unsigned int loc,
unsigned int content)
{
unsigned int off;
sector_t sec;
__le32 *fat_entry;
struct buffer_head *bh;
sec = FAT_ENT_OFFSET_SECTOR(sb, loc);
off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc);
bh = sb_bread(sb, sec);
if (!bh)
return -EIO;
fat_entry = (__le32 *)&(bh->b_data[off]);
*fat_entry = cpu_to_le32(content);
exfat_update_bh(sb, bh, sb->s_flags & SB_SYNCHRONOUS);
exfat_mirror_bh(sb, sec, bh);
brelse(bh);
return 0;
}
static inline bool is_valid_cluster(struct exfat_sb_info *sbi,
unsigned int clus)
{
if (clus < EXFAT_FIRST_CLUSTER || sbi->num_clusters <= clus)
return false;
return true;
}
s32 exfat_ent_get(struct super_block *sb, u32 loc, u32 *content)
int exfat_ent_get(struct super_block *sb, unsigned int loc,
unsigned int *content)
{
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
u32 off, _content;
u64 sec;
u8 *fat_sector;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
int err;
if (!is_valid_clus(fsi, loc)) {
exfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", loc);
if (!is_valid_cluster(sbi, loc)) {
exfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)",
loc);
return -EIO;
}
sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-2));
off = (loc << 2) & (u32)(sb->s_blocksize - 1);
fat_sector = exfat_fcache_getblk(sb, sec);
if (!fat_sector) {
exfat_fs_error(sb, "failed to access to FAT "
"(entry 0x%08x)", loc);
return -EIO;
}
_content = le32_to_cpu(*(__le32 *)(&fat_sector[off]));
/* remap reserved clusters to simplify code */
if (_content >= CLUSTER_32(0xFFFFFFF8))
_content = CLUS_EOF;
*content = CLUSTER_32(_content);
if (!is_reserved_clus(*content) && !is_valid_clus(fsi, *content)) {
exfat_fs_error(sb, "invalid access to FAT (entry 0x%08x) "
"bogus content (0x%08x)", loc, *content);
return -EIO;
}
return 0;
}
s32 exfat_ent_set(struct super_block *sb, u32 loc, u32 content)
{
u32 off;
u64 sec;
u8 *fat_sector;
__le32 *fat_entry;
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-2));
off = (loc << 2) & (u32)(sb->s_blocksize - 1);
fat_sector = exfat_fcache_getblk(sb, sec);
if (!fat_sector)
return -EIO;
fat_entry = (__le32 *)&(fat_sector[off]);
*fat_entry = cpu_to_le32(content);
return exfat_fcache_modify(sb, sec);
}
s32 exfat_ent_get_safe(struct super_block *sb, u32 loc, u32 *content)
{
s32 err = exfat_ent_get(sb, loc, content);
if (err)
err = __exfat_ent_get(sb, loc, content);
if (err) {
exfat_fs_error(sb,
"failed to access to FAT (entry 0x%08x, err:%d)",
loc, err);
return err;
}
if (IS_CLUS_FREE(*content)) {
exfat_fs_error(sb, "invalid access to FAT free cluster "
"(entry 0x%08x)", loc);
if (*content == EXFAT_FREE_CLUSTER) {
exfat_fs_error(sb,
"invalid access to FAT free cluster (entry 0x%08x)",
loc);
return -EIO;
}
if (IS_CLUS_BAD(*content)) {
exfat_fs_error(sb, "invalid access to FAT bad cluster "
"(entry 0x%08x)", loc);
if (*content == EXFAT_BAD_CLUSTER) {
exfat_fs_error(sb,
"invalid access to FAT bad cluster (entry 0x%08x)",
loc);
return -EIO;
}
if (*content != EXFAT_EOF_CLUSTER && !is_valid_cluster(sbi, *content)) {
exfat_fs_error(sb,
"invalid access to FAT (entry 0x%08x) bogus content (0x%08x)",
loc, *content);
return -EIO;
}
return 0;
}
int exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain,
unsigned int len)
{
if (!len)
return 0;
while (len > 1) {
if (exfat_ent_set(sb, chain, chain + 1))
return -EIO;
chain++;
len--;
}
if (exfat_ent_set(sb, chain, EXFAT_EOF_CLUSTER))
return -EIO;
return 0;
}
int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
{
unsigned int num_clusters = 0;
unsigned int clu;
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
/* invalid cluster number */
if (p_chain->dir == EXFAT_FREE_CLUSTER ||
p_chain->dir == EXFAT_EOF_CLUSTER ||
p_chain->dir < EXFAT_FIRST_CLUSTER)
return 0;
/* no cluster to truncate */
if (p_chain->size == 0)
return 0;
/* check cluster validation */
if (!is_valid_cluster(sbi, p_chain->dir)) {
exfat_err(sb, "invalid start cluster (%u)", p_chain->dir);
return -EIO;
}
set_bit(EXFAT_SB_DIRTY, &sbi->s_state);
clu = p_chain->dir;
if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
do {
exfat_clear_bitmap(inode, clu);
clu++;
num_clusters++;
} while (num_clusters < p_chain->size);
} else {
do {
exfat_clear_bitmap(inode, clu);
if (exfat_get_next_cluster(sb, &clu))
goto dec_used_clus;
num_clusters++;
} while (clu != EXFAT_EOF_CLUSTER);
}
dec_used_clus:
sbi->used_clusters -= num_clusters;
return 0;
}
int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain,
unsigned int *ret_clu)
{
unsigned int clu, next;
unsigned int count = 0;
next = p_chain->dir;
if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
*ret_clu = next + p_chain->size - 1;
return 0;
}
do {
count++;
clu = next;
if (exfat_ent_get(sb, clu, &next))
return -EIO;
} while (next != EXFAT_EOF_CLUSTER);
if (p_chain->size != count) {
exfat_fs_error(sb,
"bogus directory size (clus : ondisk(%d) != counted(%d))",
p_chain->size, count);
return -EIO;
}
*ret_clu = clu;
return 0;
}
static inline int exfat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
{
int i, err = 0;
for (i = 0; i < nr_bhs; i++)
write_dirty_buffer(bhs[i], 0);
for (i = 0; i < nr_bhs; i++) {
wait_on_buffer(bhs[i]);
if (!err && !buffer_uptodate(bhs[i]))
err = -EIO;
}
return err;
}
int exfat_zeroed_cluster(struct inode *dir, unsigned int clu)
{
struct super_block *sb = dir->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct buffer_head *bhs[MAX_BUF_PER_PAGE];
int nr_bhs = MAX_BUF_PER_PAGE;
sector_t blknr, last_blknr;
int err, i, n;
blknr = exfat_cluster_to_sector(sbi, clu);
last_blknr = blknr + sbi->sect_per_clus;
if (last_blknr > sbi->num_sectors && sbi->num_sectors > 0) {
exfat_fs_error_ratelimit(sb,
"%s: out of range(sect:%llu len:%u)",
__func__, (unsigned long long)blknr,
sbi->sect_per_clus);
return -EIO;
}
/* Zeroing the unused blocks on this cluster */
n = 0;
while (blknr < last_blknr) {
bhs[n] = sb_getblk(sb, blknr);
if (!bhs[n]) {
err = -ENOMEM;
goto release_bhs;
}
memset(bhs[n]->b_data, 0, sb->s_blocksize);
exfat_update_bh(sb, bhs[n], 0);
n++;
blknr++;
if (n == nr_bhs) {
if (IS_DIRSYNC(dir)) {
err = exfat_sync_bhs(bhs, n);
if (err)
goto release_bhs;
}
for (i = 0; i < n; i++)
brelse(bhs[i]);
n = 0;
}
}
if (IS_DIRSYNC(dir)) {
err = exfat_sync_bhs(bhs, n);
if (err)
goto release_bhs;
}
for (i = 0; i < n; i++)
brelse(bhs[i]);
return 0;
release_bhs:
exfat_err(sb, "failed zeroed sect %llu\n", (unsigned long long)blknr);
for (i = 0; i < n; i++)
bforget(bhs[i]);
return err;
}
int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc,
struct exfat_chain *p_chain)
{
int ret = -ENOSPC;
unsigned int num_clusters = 0, total_cnt;
unsigned int hint_clu, new_clu, last_clu = EXFAT_EOF_CLUSTER;
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
total_cnt = EXFAT_DATA_CLUSTER_COUNT(sbi);
if (unlikely(total_cnt < sbi->used_clusters)) {
exfat_fs_error_ratelimit(sb,
"%s: invalid used clusters(t:%u,u:%u)\n",
__func__, total_cnt, sbi->used_clusters);
return -EIO;
}
if (num_alloc > total_cnt - sbi->used_clusters)
return -ENOSPC;
hint_clu = p_chain->dir;
/* find new cluster */
if (hint_clu == EXFAT_EOF_CLUSTER) {
if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) {
exfat_err(sb, "sbi->clu_srch_ptr is invalid (%u)\n",
sbi->clu_srch_ptr);
sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER;
}
hint_clu = exfat_find_free_bitmap(sb, sbi->clu_srch_ptr);
if (hint_clu == EXFAT_EOF_CLUSTER)
return -ENOSPC;
}
/* check cluster validation */
if (!is_valid_cluster(sbi, hint_clu)) {
exfat_err(sb, "hint_cluster is invalid (%u)",
hint_clu);
hint_clu = EXFAT_FIRST_CLUSTER;
if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
if (exfat_chain_cont_cluster(sb, p_chain->dir,
num_clusters))
return -EIO;
p_chain->flags = ALLOC_FAT_CHAIN;
}
}
set_bit(EXFAT_SB_DIRTY, &sbi->s_state);
p_chain->dir = EXFAT_EOF_CLUSTER;
while ((new_clu = exfat_find_free_bitmap(sb, hint_clu)) !=
EXFAT_EOF_CLUSTER) {
if (new_clu != hint_clu &&
p_chain->flags == ALLOC_NO_FAT_CHAIN) {
if (exfat_chain_cont_cluster(sb, p_chain->dir,
num_clusters)) {
ret = -EIO;
goto free_cluster;
}
p_chain->flags = ALLOC_FAT_CHAIN;
}
/* update allocation bitmap */
if (exfat_set_bitmap(inode, new_clu)) {
ret = -EIO;
goto free_cluster;
}
num_clusters++;
/* update FAT table */
if (p_chain->flags == ALLOC_FAT_CHAIN) {
if (exfat_ent_set(sb, new_clu, EXFAT_EOF_CLUSTER)) {
ret = -EIO;
goto free_cluster;
}
}
if (p_chain->dir == EXFAT_EOF_CLUSTER) {
p_chain->dir = new_clu;
} else if (p_chain->flags == ALLOC_FAT_CHAIN) {
if (exfat_ent_set(sb, last_clu, new_clu)) {
ret = -EIO;
goto free_cluster;
}
}
last_clu = new_clu;
if (--num_alloc == 0) {
sbi->clu_srch_ptr = hint_clu;
sbi->used_clusters += num_clusters;
p_chain->size += num_clusters;
return 0;
}
hint_clu = new_clu + 1;
if (hint_clu >= sbi->num_clusters) {
hint_clu = EXFAT_FIRST_CLUSTER;
if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
if (exfat_chain_cont_cluster(sb, p_chain->dir,
num_clusters)) {
ret = -EIO;
goto free_cluster;
}
p_chain->flags = ALLOC_FAT_CHAIN;
}
}
}
free_cluster:
if (num_clusters)
exfat_free_cluster(inode, p_chain);
return ret;
}
int exfat_count_num_clusters(struct super_block *sb,
struct exfat_chain *p_chain, unsigned int *ret_count)
{
unsigned int i, count;
unsigned int clu;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) {
*ret_count = 0;
return 0;
}
if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
*ret_count = p_chain->size;
return 0;
}
clu = p_chain->dir;
count = 0;
for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; i++) {
count++;
if (exfat_ent_get(sb, clu, &clu))
return -EIO;
if (clu == EXFAT_EOF_CLUSTER)
break;
}
*ret_count = count;
return 0;
}

403
fs/exfat/file.c Normal file
View File

@ -0,0 +1,403 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#include <linux/slab.h>
#include <linux/cred.h>
#include <linux/buffer_head.h>
#include <linux/blkdev.h>
#include "exfat_fs.h"
static int exfat_cont_expand(struct inode *inode, loff_t size)
{
struct address_space *mapping = inode->i_mapping;
loff_t start = i_size_read(inode), count = size - i_size_read(inode);
int err, err2;
err = generic_cont_expand_simple(inode, size);
if (err)
return err;
inode->i_ctime = inode->i_mtime = current_time(inode);
mark_inode_dirty(inode);
if (!IS_SYNC(inode))
return 0;
err = filemap_fdatawrite_range(mapping, start, start + count - 1);
err2 = sync_mapping_buffers(mapping);
if (!err)
err = err2;
err2 = write_inode_now(inode, 1);
if (!err)
err = err2;
if (err)
return err;
return filemap_fdatawait_range(mapping, start, start + count - 1);
}
static bool exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode)
{
mode_t allow_utime = sbi->options.allow_utime;
if (!uid_eq(current_fsuid(), inode->i_uid)) {
if (in_group_p(inode->i_gid))
allow_utime >>= 3;
if (allow_utime & MAY_WRITE)
return true;
}
/* use a default check */
return false;
}
static int exfat_sanitize_mode(const struct exfat_sb_info *sbi,
struct inode *inode, umode_t *mode_ptr)
{
mode_t i_mode, mask, perm;
i_mode = inode->i_mode;
mask = (S_ISREG(i_mode) || S_ISLNK(i_mode)) ?
sbi->options.fs_fmask : sbi->options.fs_dmask;
perm = *mode_ptr & ~(S_IFMT | mask);
/* Of the r and x bits, all (subject to umask) must be present.*/
if ((perm & 0555) != (i_mode & 0555))
return -EPERM;
if (exfat_mode_can_hold_ro(inode)) {
/*
* Of the w bits, either all (subject to umask) or none must
* be present.
*/
if ((perm & 0222) && ((perm & 0222) != (0222 & ~mask)))
return -EPERM;
} else {
/*
* If exfat_mode_can_hold_ro(inode) is false, can't change
* w bits.
*/
if ((perm & 0222) != (0222 & ~mask))
return -EPERM;
}
*mode_ptr &= S_IFMT | perm;
return 0;
}
/* resize the file length */
int __exfat_truncate(struct inode *inode, loff_t new_size)
{
unsigned int num_clusters_new, num_clusters_phys;
unsigned int last_clu = EXFAT_FREE_CLUSTER;
struct exfat_chain clu;
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_inode_info *ei = EXFAT_I(inode);
int evict = (ei->dir.dir == DIR_DELETED) ? 1 : 0;
/* check if the given file ID is opened */
if (ei->type != TYPE_FILE && ei->type != TYPE_DIR)
return -EPERM;
exfat_set_vol_flags(sb, VOL_DIRTY);
num_clusters_new = EXFAT_B_TO_CLU_ROUND_UP(i_size_read(inode), sbi);
num_clusters_phys =
EXFAT_B_TO_CLU_ROUND_UP(EXFAT_I(inode)->i_size_ondisk, sbi);
exfat_chain_set(&clu, ei->start_clu, num_clusters_phys, ei->flags);
if (new_size > 0) {
/*
* Truncate FAT chain num_clusters after the first cluster
* num_clusters = min(new, phys);
*/
unsigned int num_clusters =
min(num_clusters_new, num_clusters_phys);
/*
* Follow FAT chain
* (defensive coding - works fine even with corrupted FAT table
*/
if (clu.flags == ALLOC_NO_FAT_CHAIN) {
clu.dir += num_clusters;
clu.size -= num_clusters;
} else {
while (num_clusters > 0) {
last_clu = clu.dir;
if (exfat_get_next_cluster(sb, &(clu.dir)))
return -EIO;
num_clusters--;
clu.size--;
}
}
} else {
ei->flags = ALLOC_NO_FAT_CHAIN;
ei->start_clu = EXFAT_EOF_CLUSTER;
}
i_size_write(inode, new_size);
if (ei->type == TYPE_FILE)
ei->attr |= ATTR_ARCHIVE;
/* update the directory entry */
if (!evict) {
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_ALL_ENTRIES);
if (!es)
return -EIO;
ep = exfat_get_dentry_cached(es, 0);
ep2 = exfat_get_dentry_cached(es, 1);
ts = current_time(inode);
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_cs);
ep->dentry.file.attr = cpu_to_le16(ei->attr);
/* File size should be zero if there is no cluster allocated */
if (ei->start_clu == EXFAT_EOF_CLUSTER) {
ep2->dentry.stream.valid_size = 0;
ep2->dentry.stream.size = 0;
} else {
ep2->dentry.stream.valid_size = cpu_to_le64(new_size);
ep2->dentry.stream.size = ep->dentry.stream.valid_size;
}
if (new_size == 0) {
/* Any directory can not be truncated to zero */
WARN_ON(ei->type != TYPE_FILE);
ep2->dentry.stream.flags = ALLOC_FAT_CHAIN;
ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER;
}
exfat_update_dir_chksum_with_entry_set(es);
exfat_free_dentry_set(es, inode_needs_sync(inode));
}
/* cut off from the FAT chain */
if (ei->flags == ALLOC_FAT_CHAIN && last_clu != EXFAT_FREE_CLUSTER &&
last_clu != EXFAT_EOF_CLUSTER) {
if (exfat_ent_set(sb, last_clu, EXFAT_EOF_CLUSTER))
return -EIO;
}
/* invalidate cache and free the clusters */
/* clear exfat cache */
exfat_cache_inval_inode(inode);
/* hint information */
ei->hint_bmap.off = EXFAT_EOF_CLUSTER;
ei->hint_bmap.clu = EXFAT_EOF_CLUSTER;
if (ei->rwoffset > new_size)
ei->rwoffset = new_size;
/* hint_stat will be used if this is directory. */
ei->hint_stat.eidx = 0;
ei->hint_stat.clu = ei->start_clu;
ei->hint_femp.eidx = EXFAT_HINT_NONE;
/* free the clusters */
if (exfat_free_cluster(inode, &clu))
return -EIO;
exfat_set_vol_flags(sb, VOL_CLEAN);
return 0;
}
void exfat_truncate(struct inode *inode, loff_t size)
{
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
unsigned int blocksize = 1 << inode->i_blkbits;
loff_t aligned_size;
int err;
mutex_lock(&sbi->s_lock);
if (EXFAT_I(inode)->start_clu == 0) {
/*
* Empty start_clu != ~0 (not allocated)
*/
exfat_fs_error(sb, "tried to truncate zeroed cluster.");
goto write_size;
}
err = __exfat_truncate(inode, i_size_read(inode));
if (err)
goto write_size;
inode->i_ctime = inode->i_mtime = current_time(inode);
if (IS_DIRSYNC(inode))
exfat_sync_inode(inode);
else
mark_inode_dirty(inode);
inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) &
~(sbi->cluster_size - 1)) >> inode->i_blkbits;
write_size:
aligned_size = i_size_read(inode);
if (aligned_size & (blocksize - 1)) {
aligned_size |= (blocksize - 1);
aligned_size++;
}
if (EXFAT_I(inode)->i_size_ondisk > i_size_read(inode))
EXFAT_I(inode)->i_size_ondisk = aligned_size;
if (EXFAT_I(inode)->i_size_aligned > i_size_read(inode))
EXFAT_I(inode)->i_size_aligned = aligned_size;
mutex_unlock(&sbi->s_lock);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
int exfat_getattr(const struct path *path, struct kstat *stat,
unsigned int request_mask, unsigned int query_flags)
{
struct inode *inode = d_backing_inode(path->dentry);
struct exfat_inode_info *ei = EXFAT_I(inode);
generic_fillattr(inode, stat);
exfat_truncate_atime(&stat->atime);
stat->result_mask |= STATX_BTIME;
stat->btime.tv_sec = ei->i_crtime.tv_sec;
stat->btime.tv_nsec = ei->i_crtime.tv_nsec;
stat->blksize = EXFAT_SB(inode->i_sb)->cluster_size;
return 0;
}
#else
int exfat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{
struct inode *inode = dentry->d_inode;
generic_fillattr(inode, stat);
exfat_truncate_atime(&stat->atime);
stat->blksize = EXFAT_SB(inode->i_sb)->cluster_size;
return 0;
}
#endif
int exfat_setattr(struct dentry *dentry, struct iattr *attr)
{
struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb);
struct inode *inode = dentry->d_inode;
unsigned int ia_valid;
int error;
if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size > i_size_read(inode)) {
error = exfat_cont_expand(inode, attr->ia_size);
if (error || attr->ia_valid == ATTR_SIZE)
goto out;
attr->ia_valid &= ~ATTR_SIZE;
}
/* Check for setting the inode time. */
ia_valid = attr->ia_valid;
if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) &&
exfat_allow_set_time(sbi, inode)) {
attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET |
ATTR_TIMES_SET);
}
error = setattr_prepare(dentry, attr);
attr->ia_valid = ia_valid;
if (error) {
if (sbi->options.quiet)
error = 0;
goto out;
}
if (((attr->ia_valid & ATTR_UID) &&
!uid_eq(attr->ia_uid, sbi->options.fs_uid)) ||
((attr->ia_valid & ATTR_GID) &&
!gid_eq(attr->ia_gid, sbi->options.fs_gid)) ||
((attr->ia_valid & ATTR_MODE) &&
(attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | 0777)))) {
error = -EPERM;
goto out;
}
if (error) {
if (sbi->options.quiet)
error = 0;
goto out;
}
/*
* We don't return -EPERM here. Yes, strange, but this is too
* old behavior.
*/
if (attr->ia_valid & ATTR_MODE) {
if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0)
attr->ia_valid &= ~ATTR_MODE;
}
if (attr->ia_valid & ATTR_SIZE) {
error = exfat_block_truncate_page(inode, attr->ia_size);
if (error)
goto out;
down_write(&EXFAT_I(inode)->truncate_lock);
truncate_setsize(inode, attr->ia_size);
exfat_truncate(inode, attr->ia_size);
up_write(&EXFAT_I(inode)->truncate_lock);
}
setattr_copy(inode, attr);
exfat_truncate_atime(&inode->i_atime);
mark_inode_dirty(inode);
out:
return error;
}
int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
{
struct inode *inode = filp->f_mapping->host;
int err;
err = __generic_file_fsync(filp, start, end, datasync);
if (err)
return err;
err = sync_blockdev(inode->i_sb->s_bdev);
if (err)
return err;
return blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
}
const struct file_operations exfat_file_operations = {
.llseek = generic_file_llseek,
.read_iter = generic_file_read_iter,
.write_iter = generic_file_write_iter,
.mmap = generic_file_mmap,
.fsync = exfat_file_fsync,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
};
const struct inode_operations exfat_file_inode_operations = {
.setattr = exfat_setattr,
.getattr = exfat_getattr,
#ifdef CONFIG_EXFAT_VIRTUAL_XATTR
.listxattr = exfat_listxattr,
#endif
};

660
fs/exfat/inode.c Normal file
View File

@ -0,0 +1,660 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#include <linux/init.h>
#include <linux/buffer_head.h>
#include <linux/mpage.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/time.h>
#include <linux/writeback.h>
#include <linux/uio.h>
#include <linux/random.h>
#include "exfat_fs.h"
static int __exfat_write_inode(struct inode *inode, int sync)
{
unsigned long long on_disk_size;
struct exfat_dentry *ep, *ep2;
struct exfat_entry_set_cache *es = NULL;
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_inode_info *ei = EXFAT_I(inode);
bool is_dir = (ei->type == TYPE_DIR) ? true : false;
if (inode->i_ino == EXFAT_ROOT_INO)
return 0;
/*
* If the indode is already unlinked, there is no need for updating it.
*/
if (ei->dir.dir == DIR_DELETED)
return 0;
if (is_dir && ei->dir.dir == sbi->root_dir && ei->entry == -1)
return 0;
exfat_set_vol_flags(sb, VOL_DIRTY);
/* get the directory entry of given file or directory */
es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES);
if (!es)
return -EIO;
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));
/* set FILE_INFO structure using the acquired struct exfat_dentry */
exfat_set_entry_time(sbi, &ei->i_crtime,
&ep->dentry.file.create_tz,
&ep->dentry.file.create_time,
&ep->dentry.file.create_date,
&ep->dentry.file.create_time_cs);
exfat_set_entry_time(sbi, &inode->i_mtime,
&ep->dentry.file.modify_tz,
&ep->dentry.file.modify_time,
&ep->dentry.file.modify_date,
&ep->dentry.file.modify_time_cs);
exfat_set_entry_time(sbi, &inode->i_atime,
&ep->dentry.file.access_tz,
&ep->dentry.file.access_time,
&ep->dentry.file.access_date,
NULL);
/* File size should be zero if there is no cluster allocated */
on_disk_size = i_size_read(inode);
if (ei->start_clu == EXFAT_EOF_CLUSTER)
on_disk_size = 0;
ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size);
ep2->dentry.stream.size = ep2->dentry.stream.valid_size;
exfat_update_dir_chksum_with_entry_set(es);
exfat_free_dentry_set(es, sync);
return 0;
}
int exfat_write_inode(struct inode *inode, struct writeback_control *wbc)
{
int ret;
mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock);
ret = __exfat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock);
return ret;
}
void exfat_sync_inode(struct inode *inode)
{
lockdep_assert_held(&EXFAT_SB(inode->i_sb)->s_lock);
__exfat_write_inode(inode, 1);
}
/*
* Input: inode, (logical) clu_offset, target allocation area
* Output: errcode, cluster number
* *clu = (~0), if it's unable to allocate a new cluster
*/
static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
unsigned int *clu, int create)
{
int ret, modified = false;
unsigned int last_clu;
struct exfat_chain new_clu;
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_inode_info *ei = EXFAT_I(inode);
unsigned int local_clu_offset = clu_offset;
unsigned int num_to_be_allocated = 0, num_clusters = 0;
ei->rwoffset = EXFAT_CLU_TO_B(clu_offset, sbi);
if (EXFAT_I(inode)->i_size_ondisk > 0)
num_clusters =
EXFAT_B_TO_CLU_ROUND_UP(EXFAT_I(inode)->i_size_ondisk,
sbi);
if (clu_offset >= num_clusters)
num_to_be_allocated = clu_offset - num_clusters + 1;
if (!create && (num_to_be_allocated > 0)) {
*clu = EXFAT_EOF_CLUSTER;
return 0;
}
*clu = last_clu = ei->start_clu;
if (ei->flags == ALLOC_NO_FAT_CHAIN) {
if (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) {
last_clu += clu_offset - 1;
if (clu_offset == num_clusters)
*clu = EXFAT_EOF_CLUSTER;
else
*clu += clu_offset;
}
} else if (ei->type == TYPE_FILE) {
unsigned int fclus = 0;
int err = exfat_get_cluster(inode, clu_offset,
&fclus, clu, &last_clu, 1);
if (err)
return -EIO;
clu_offset -= fclus;
} else {
/* hint information */
if (clu_offset > 0 && ei->hint_bmap.off != EXFAT_EOF_CLUSTER &&
ei->hint_bmap.off > 0 && clu_offset >= ei->hint_bmap.off) {
clu_offset -= ei->hint_bmap.off;
/* hint_bmap.clu should be valid */
WARN_ON(ei->hint_bmap.clu < 2);
*clu = ei->hint_bmap.clu;
}
while (clu_offset > 0 && *clu != EXFAT_EOF_CLUSTER) {
last_clu = *clu;
if (exfat_get_next_cluster(sb, clu))
return -EIO;
clu_offset--;
}
}
if (*clu == EXFAT_EOF_CLUSTER) {
exfat_set_vol_flags(sb, VOL_DIRTY);
new_clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ?
EXFAT_EOF_CLUSTER : last_clu + 1;
new_clu.size = 0;
new_clu.flags = ei->flags;
/* allocate a cluster */
if (num_to_be_allocated < 1) {
/* Broken FAT (i_sze > allocated FAT) */
exfat_fs_error(sb, "broken FAT chain.");
return -EIO;
}
ret = exfat_alloc_cluster(inode, num_to_be_allocated, &new_clu);
if (ret)
return ret;
if (new_clu.dir == EXFAT_EOF_CLUSTER ||
new_clu.dir == EXFAT_FREE_CLUSTER) {
exfat_fs_error(sb,
"bogus cluster new allocated (last_clu : %u, new_clu : %u)",
last_clu, new_clu.dir);
return -EIO;
}
/* append to the FAT chain */
if (last_clu == EXFAT_EOF_CLUSTER) {
if (new_clu.flags == ALLOC_FAT_CHAIN)
ei->flags = ALLOC_FAT_CHAIN;
ei->start_clu = new_clu.dir;
modified = true;
} else {
if (new_clu.flags != ei->flags) {
/* no-fat-chain bit is disabled,
* so fat-chain should be synced with
* alloc-bitmap
*/
exfat_chain_cont_cluster(sb, ei->start_clu,
num_clusters);
ei->flags = ALLOC_FAT_CHAIN;
modified = true;
}
if (new_clu.flags == ALLOC_FAT_CHAIN)
if (exfat_ent_set(sb, last_clu, new_clu.dir))
return -EIO;
}
num_clusters += num_to_be_allocated;
*clu = new_clu.dir;
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_ALL_ENTRIES);
if (!es)
return -EIO;
/* get stream entry */
ep = exfat_get_dentry_cached(es, 1);
/* update directory entry */
ep->dentry.stream.flags = ei->flags;
ep->dentry.stream.start_clu =
cpu_to_le32(ei->start_clu);
ep->dentry.stream.valid_size =
cpu_to_le64(i_size_read(inode));
ep->dentry.stream.size =
ep->dentry.stream.valid_size;
exfat_update_dir_chksum_with_entry_set(es);
exfat_free_dentry_set(es, inode_needs_sync(inode));
} /* end of if != DIR_DELETED */
inode->i_blocks +=
num_to_be_allocated << sbi->sect_per_clus_bits;
/*
* Move *clu pointer along FAT chains (hole care) because the
* caller of this function expect *clu to be the last cluster.
* This only works when num_to_be_allocated >= 2,
* *clu = (the first cluster of the allocated chain) =>
* (the last cluster of ...)
*/
if (ei->flags == ALLOC_NO_FAT_CHAIN) {
*clu += num_to_be_allocated - 1;
} else {
while (num_to_be_allocated > 1) {
if (exfat_get_next_cluster(sb, clu))
return -EIO;
num_to_be_allocated--;
}
}
}
/* hint information */
ei->hint_bmap.off = local_clu_offset;
ei->hint_bmap.clu = *clu;
return 0;
}
static int exfat_map_new_buffer(struct exfat_inode_info *ei,
struct buffer_head *bh, loff_t pos)
{
if (buffer_delay(bh) && pos > ei->i_size_aligned)
return -EIO;
set_buffer_new(bh);
/*
* Adjust i_size_aligned if i_size_ondisk is bigger than it.
*/
if (ei->i_size_ondisk > ei->i_size_aligned)
ei->i_size_aligned = ei->i_size_ondisk;
return 0;
}
static int exfat_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
struct exfat_inode_info *ei = EXFAT_I(inode);
struct super_block *sb = inode->i_sb;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
int err = 0;
unsigned long mapped_blocks = 0;
unsigned int cluster, sec_offset;
sector_t last_block;
sector_t phys = 0;
loff_t pos;
mutex_lock(&sbi->s_lock);
last_block = EXFAT_B_TO_BLK_ROUND_UP(i_size_read(inode), sb);
if (iblock >= last_block && !create)
goto done;
/* Is this block already allocated? */
err = exfat_map_cluster(inode, iblock >> sbi->sect_per_clus_bits,
&cluster, create);
if (err) {
if (err != -ENOSPC)
exfat_fs_error_ratelimit(sb,
"failed to bmap (inode : %p iblock : %llu, err : %d)",
inode, (unsigned long long)iblock, err);
goto unlock_ret;
}
if (cluster == EXFAT_EOF_CLUSTER)
goto done;
/* sector offset in cluster */
sec_offset = iblock & (sbi->sect_per_clus - 1);
phys = exfat_cluster_to_sector(sbi, cluster) + sec_offset;
mapped_blocks = sbi->sect_per_clus - sec_offset;
max_blocks = min(mapped_blocks, max_blocks);
/* Treat newly added block / cluster */
if (iblock < last_block)
create = 0;
if (create || buffer_delay(bh_result)) {
pos = EXFAT_BLK_TO_B((iblock + 1), sb);
if (ei->i_size_ondisk < pos)
ei->i_size_ondisk = pos;
}
if (create) {
err = exfat_map_new_buffer(ei, bh_result, pos);
if (err) {
exfat_fs_error(sb,
"requested for bmap out of range(pos : (%llu) > i_size_aligned(%llu)\n",
pos, ei->i_size_aligned);
goto unlock_ret;
}
}
if (buffer_delay(bh_result))
clear_buffer_delay(bh_result);
map_bh(bh_result, sb, phys);
done:
bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb);
unlock_ret:
mutex_unlock(&sbi->s_lock);
return err;
}
static int exfat_readpage(struct file *file, struct page *page)
{
return mpage_readpage(page, exfat_get_block);
}
static int exfat_readpages(struct file *file, struct address_space *mapping,
struct list_head *pages, unsigned int nr_pages)
{
return mpage_readpages(mapping, pages, nr_pages, exfat_get_block);
}
static int exfat_writepage(struct page *page, struct writeback_control *wbc)
{
return block_write_full_page(page, exfat_get_block, wbc);
}
static int exfat_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
return mpage_writepages(mapping, wbc, exfat_get_block);
}
static void exfat_write_failed(struct address_space *mapping, loff_t to)
{
struct inode *inode = mapping->host;
if (to > i_size_read(inode)) {
truncate_pagecache(inode, i_size_read(inode));
exfat_truncate(inode, EXFAT_I(inode)->i_size_aligned);
}
}
static int exfat_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned int len, unsigned int flags,
struct page **pagep, void **fsdata)
{
int ret;
*pagep = NULL;
ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
exfat_get_block,
&EXFAT_I(mapping->host)->i_size_ondisk);
if (ret < 0)
exfat_write_failed(mapping, pos+len);
return ret;
}
static int exfat_write_end(struct file *file, struct address_space *mapping,
loff_t pos, unsigned int len, unsigned int copied,
struct page *pagep, void *fsdata)
{
struct inode *inode = mapping->host;
struct exfat_inode_info *ei = EXFAT_I(inode);
int err;
err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
if (EXFAT_I(inode)->i_size_aligned < i_size_read(inode)) {
exfat_fs_error(inode->i_sb,
"invalid size(size(%llu) > aligned(%llu)\n",
i_size_read(inode), EXFAT_I(inode)->i_size_aligned);
return -EIO;
}
if (err < len)
exfat_write_failed(mapping, pos+len);
if (!(err < 0) && !(ei->attr & ATTR_ARCHIVE)) {
inode->i_mtime = inode->i_ctime = current_time(inode);
ei->attr |= ATTR_ARCHIVE;
mark_inode_dirty(inode);
}
return err;
}
static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
{
struct address_space *mapping = iocb->ki_filp->f_mapping;
struct inode *inode = mapping->host;
loff_t size = iocb->ki_pos + iov_iter_count(iter);
int rw = iov_iter_rw(iter);
ssize_t ret;
if (rw == WRITE) {
/*
* FIXME: blockdev_direct_IO() doesn't use ->write_begin(),
* so we need to update the ->i_size_aligned to block boundary.
*
* But we must fill the remaining area or hole by nul for
* updating ->i_size_aligned
*
* Return 0, and fallback to normal buffered write.
*/
if (EXFAT_I(inode)->i_size_aligned < size)
return 0;
}
/*
* Need to use the DIO_LOCKING for avoiding the race
* condition of exfat_get_block() and ->truncate().
*/
ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block);
if (ret < 0 && (rw & WRITE))
exfat_write_failed(mapping, size);
return ret;
}
static sector_t exfat_aop_bmap(struct address_space *mapping, sector_t block)
{
sector_t blocknr;
/* exfat_get_cluster() assumes the requested blocknr isn't truncated. */
down_read(&EXFAT_I(mapping->host)->truncate_lock);
blocknr = generic_block_bmap(mapping, block, exfat_get_block);
up_read(&EXFAT_I(mapping->host)->truncate_lock);
return blocknr;
}
/*
* exfat_block_truncate_page() zeroes out a mapping from file offset `from'
* up to the end of the block which corresponds to `from'.
* This is required during truncate to physically zeroout the tail end
* of that block so it doesn't yield old data if the file is later grown.
* Also, avoid causing failure from fsx for cases of "data past EOF"
*/
int exfat_block_truncate_page(struct inode *inode, loff_t from)
{
return block_truncate_page(inode->i_mapping, from, exfat_get_block);
}
static const struct address_space_operations exfat_aops = {
.readpage = exfat_readpage,
.readpages = exfat_readpages,
.writepage = exfat_writepage,
.writepages = exfat_writepages,
.write_begin = exfat_write_begin,
.write_end = exfat_write_end,
.direct_IO = exfat_direct_IO,
.bmap = exfat_aop_bmap
};
static inline unsigned long exfat_hash(loff_t i_pos)
{
return hash_32(i_pos, EXFAT_HASH_BITS);
}
void exfat_hash_inode(struct inode *inode, loff_t i_pos)
{
struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos);
spin_lock(&sbi->inode_hash_lock);
EXFAT_I(inode)->i_pos = i_pos;
hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head);
spin_unlock(&sbi->inode_hash_lock);
}
void exfat_unhash_inode(struct inode *inode)
{
struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
spin_lock(&sbi->inode_hash_lock);
hlist_del_init(&EXFAT_I(inode)->i_hash_fat);
EXFAT_I(inode)->i_pos = 0;
spin_unlock(&sbi->inode_hash_lock);
}
struct inode *exfat_iget(struct super_block *sb, loff_t i_pos)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct exfat_inode_info *info;
struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos);
struct inode *inode = NULL;
spin_lock(&sbi->inode_hash_lock);
hlist_for_each_entry(info, head, i_hash_fat) {
WARN_ON(info->vfs_inode.i_sb != sb);
if (i_pos != info->i_pos)
continue;
inode = igrab(&info->vfs_inode);
if (inode)
break;
}
spin_unlock(&sbi->inode_hash_lock);
return inode;
}
/* doesn't deal with root inode */
static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
{
struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
struct exfat_inode_info *ei = EXFAT_I(inode);
loff_t size = info->size;
memcpy(&ei->dir, &info->dir, sizeof(struct exfat_chain));
ei->entry = info->entry;
ei->attr = info->attr;
ei->start_clu = info->start_clu;
ei->flags = info->flags;
ei->type = info->type;
ei->version = 0;
ei->hint_stat.eidx = 0;
ei->hint_stat.clu = info->start_clu;
ei->hint_femp.eidx = EXFAT_HINT_NONE;
ei->rwoffset = 0;
ei->hint_bmap.off = EXFAT_EOF_CLUSTER;
ei->i_pos = 0;
inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid;
inode_inc_iversion(inode);
inode->i_generation = prandom_u32();
if (info->attr & ATTR_SUBDIR) { /* directory */
inode->i_generation &= ~1;
inode->i_mode = exfat_make_mode(sbi, info->attr, 0777);
inode->i_op = &exfat_dir_inode_operations;
inode->i_fop = &exfat_dir_operations;
set_nlink(inode, info->num_subdirs);
} else { /* regular file */
inode->i_generation |= 1;
inode->i_mode = exfat_make_mode(sbi, info->attr, 0777);
inode->i_op = &exfat_file_inode_operations;
inode->i_fop = &exfat_file_operations;
inode->i_mapping->a_ops = &exfat_aops;
inode->i_mapping->nrpages = 0;
}
i_size_write(inode, size);
/* ondisk and aligned size should be aligned with block size */
if (size & (inode->i_sb->s_blocksize - 1)) {
size |= (inode->i_sb->s_blocksize - 1);
size++;
}
ei->i_size_aligned = size;
ei->i_size_ondisk = size;
exfat_save_attr(inode, info->attr);
inode->i_blocks = ((i_size_read(inode) + (sbi->cluster_size - 1)) &
~(sbi->cluster_size - 1)) >> inode->i_blkbits;
inode->i_mtime = info->mtime;
inode->i_ctime = info->mtime;
ei->i_crtime = info->crtime;
inode->i_atime = info->atime;
exfat_cache_init_inode(inode);
return 0;
}
struct inode *exfat_build_inode(struct super_block *sb,
struct exfat_dir_entry *info, loff_t i_pos)
{
struct inode *inode;
int err;
inode = exfat_iget(sb, i_pos);
if (inode)
goto out;
inode = new_inode(sb);
if (!inode) {
inode = ERR_PTR(-ENOMEM);
goto out;
}
inode->i_ino = iunique(sb, EXFAT_ROOT_INO);
inode_set_iversion(inode, 1);
err = exfat_fill_inode(inode, info);
if (err) {
iput(inode);
inode = ERR_PTR(err);
goto out;
}
exfat_hash_inode(inode, i_pos);
insert_inode_hash(inode);
out:
return inode;
}
void exfat_evict_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
if (!inode->i_nlink) {
i_size_write(inode, 0);
mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock);
__exfat_truncate(inode, 0);
mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock);
}
invalidate_inode_buffers(inode);
clear_inode(inode);
exfat_cache_inval_inode(inode);
exfat_unhash_inode(inode);
}

View File

@ -1,61 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*
* misc.c: Helper function for checksum and handling exFAT errors
*/
/*
* linux/fs/fat/misc.c
*
* Written 1992,1993 by Werner Almesberger
* 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980
* and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru)
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/buffer_head.h>
#include <linux/time.h>
#include "exfat.h"
#include "version.h"
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/buffer_head.h>
#ifdef CONFIG_EXFAT_UEVENT
static struct kobject exfat_uevent_kobj;
int exfat_uevent_init(struct kset *exfat_kset)
{
int err;
struct kobj_type *ktype = get_ktype(&exfat_kset->kobj);
exfat_uevent_kobj.kset = exfat_kset;
err = kobject_init_and_add(&exfat_uevent_kobj, ktype, NULL, "uevent");
if (err)
pr_err("[EXFAT] Unable to create exfat uevent kobj\n");
return err;
}
void exfat_uevent_uninit(void)
{
kobject_del(&exfat_uevent_kobj);
memset(&exfat_uevent_kobj, 0, sizeof(struct kobject));
}
void exfat_uevent_ro_remount(struct super_block *sb)
{
struct block_device *bdev = sb->s_bdev;
dev_t bd_dev = bdev ? bdev->bd_dev : 0;
char major[16], minor[16];
char *envp[] = { major, minor, NULL };
snprintf(major, sizeof(major), "MAJOR=%d", MAJOR(bd_dev));
snprintf(minor, sizeof(minor), "MINOR=%d", MINOR(bd_dev));
kobject_uevent_env(&exfat_uevent_kobj, KOBJ_CHANGE, envp);
}
#endif
#include "exfat_fs.h"
/*
* exfat_fs_error reports a file system problem that might indicate fa data
@ -70,224 +26,161 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
struct exfat_mount_options *opts = &EXFAT_SB(sb)->options;
va_list args;
struct va_format vaf;
struct block_device *bdev = sb->s_bdev;
dev_t bd_dev = bdev ? bdev->bd_dev : 0;
if (report) {
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
pr_err("exFAT-fs (%s[%d:%d]): ERR: %pV\n",
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf);
exfat_err(sb, "error, %pV", &vaf);
va_end(args);
}
if (opts->errors == EXFAT_ERRORS_PANIC) {
panic("exFAT-fs (%s[%d:%d]): fs panic from previous error\n",
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
} else if (opts->errors == EXFAT_ERRORS_RO && !EXFAT_IS_SB_RDONLY(sb)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
sb->s_flags |= MS_RDONLY;
#else
panic("exFAT-fs (%s): fs panic from previous error\n",
sb->s_id);
} else if (opts->errors == EXFAT_ERRORS_RO && !sb_rdonly(sb)) {
sb->s_flags |= SB_RDONLY;
#endif
pr_err("exFAT-fs (%s[%d:%d]): file-system has been set to "
"read-only\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
exfat_uevent_ro_remount(sb);
exfat_err(sb, "Filesystem has been set read-only");
}
}
EXPORT_SYMBOL(__exfat_fs_error);
/**
* __exfat_msg() - print preformated EXFAT specific messages.
* All logs except what uses exfat_fs_error() should be written by __exfat_msg()
/*
* exfat_msg() - print preformated EXFAT specific messages.
* All logs except what uses exfat_fs_error() should be written by exfat_msg()
*/
void __exfat_msg(struct super_block *sb, const char *level, int st, const char *fmt, ...)
void exfat_msg(struct super_block *sb, const char *level, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
struct block_device *bdev = sb->s_bdev;
dev_t bd_dev = bdev ? bdev->bd_dev : 0;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
/* level means KERN_ pacility level */
printk("%sexFAT-fs (%s[%d:%d]): %pV\n", level,
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf);
printk("%sexFAT-fs (%s): %pV\n", level, sb->s_id, &vaf);
va_end(args);
}
EXPORT_SYMBOL(__exfat_msg);
void exfat_log_version(void)
{
pr_info("exFAT: file-system version %s\n", EXFAT_VERSION);
}
EXPORT_SYMBOL(exfat_log_version);
/* <linux/time.h> externs sys_tz
* extern struct timezone sys_tz;
*/
#define UNIX_SECS_1980 315532800L
#if BITS_PER_LONG == 64
#define UNIX_SECS_2108 4354819200L
#endif
/* days between 1970/01/01 and 1980/01/01 (2 leap days) */
#define DAYS_DELTA_DECADE (365 * 10 + 2)
/* 120 (2100 - 1980) isn't leap year */
#define NO_LEAP_YEAR_2100 (120)
#define IS_LEAP_YEAR(y) (!((y) & 0x3) && (y) != NO_LEAP_YEAR_2100)
#define SECS_PER_MIN (60)
#define SECS_PER_HOUR (60 * SECS_PER_MIN)
#define SECS_PER_DAY (24 * SECS_PER_HOUR)
#define TIMEZONE_SEC(x) ((x) * 15 * SECS_PER_MIN)
#define MAKE_LEAP_YEAR(leap_year, year) \
do { \
/* 2100 isn't leap year */ \
if (unlikely(year > NO_LEAP_YEAR_2100)) \
leap_year = ((year + 3) / 4) - 1; \
else \
leap_year = ((year + 3) / 4); \
} while (0)
/* Linear day numbers of the respective 1sts in non-leap years. */
static time_t accum_days_in_year[] = {
/* Month : N 01 02 03 04 05 06 07 08 09 10 11 12 */
0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
};
/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
void exfat_time_fat2unix(struct exfat_sb_info *sbi, struct timespec_compat *ts,
DATE_TIME_T *tp)
static void exfat_adjust_tz(struct timespec64 *ts, u8 tz_off)
{
time_t year = tp->Year;
time_t ld; /* leap day */
if (tz_off <= 0x3F)
ts->tv_sec -= TIMEZONE_SEC(tz_off);
else /* 0x40 <= (tz_off & 0x7F) <=0x7F */
ts->tv_sec += TIMEZONE_SEC(0x80 - tz_off);
}
MAKE_LEAP_YEAR(ld, year);
/* 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,
u8 tz, __le16 time, __le16 date, u8 time_cs)
{
u16 t = le16_to_cpu(time);
u16 d = le16_to_cpu(date);
if (IS_LEAP_YEAR(year) && (tp->Month) > 2)
ld++;
ts->tv_sec = mktime64(1980 + (d >> 9), d >> 5 & 0x000F, d & 0x001F,
t >> 11, (t >> 5) & 0x003F, (t & 0x001F) << 1);
ts->tv_sec = tp->Second + tp->Minute * SECS_PER_MIN
+ tp->Hour * SECS_PER_HOUR
+ (year * 365 + ld + accum_days_in_year[tp->Month]
+ (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY;
if (!sbi->options.tz_utc)
ts->tv_sec += sys_tz.tz_minuteswest * SECS_PER_MIN;
/* time_cs field represent 0 ~ 199cs(1990 ms) */
if (time_cs) {
ts->tv_sec += time_cs / 100;
ts->tv_nsec = (time_cs % 100) * 10 * NSEC_PER_MSEC;
} else
ts->tv_nsec = 0;
if (tz & EXFAT_TZ_VALID)
/* Adjust timezone to UTC0. */
exfat_adjust_tz(ts, tz & ~EXFAT_TZ_VALID);
else
/* Convert from local time to UTC using time_offset. */
ts->tv_sec -= sbi->options.time_offset * SECS_PER_MIN;
}
/* Convert linear UNIX date to a EXFAT time/date pair. */
void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
u8 *tz, __le16 *time, __le16 *date, u8 *time_cs)
{
struct tm tm;
u16 t, d;
time64_to_tm(ts->tv_sec, 0, &tm);
t = (tm.tm_hour << 11) | (tm.tm_min << 5) | (tm.tm_sec >> 1);
d = ((tm.tm_year - 80) << 9) | ((tm.tm_mon + 1) << 5) | tm.tm_mday;
*time = cpu_to_le16(t);
*date = cpu_to_le16(d);
/* time_cs field represent 0 ~ 199cs(1990 ms) */
if (time_cs)
*time_cs = (tm.tm_sec & 1) * 100 +
ts->tv_nsec / (10 * NSEC_PER_MSEC);
/*
* Record 00h value for OffsetFromUtc field and 1 value for OffsetValid
* to indicate that local time and UTC are the same.
*/
*tz = EXFAT_TZ_VALID;
}
/*
* The timestamp for access_time has double seconds granularity.
* (There is no 10msIncrement field for access_time unlike create/modify_time)
* atime also has only a 2-second resolution.
*/
void exfat_truncate_atime(struct timespec64 *ts)
{
ts->tv_sec = round_down(ts->tv_sec, 2);
ts->tv_nsec = 0;
}
/* Convert linear UNIX date to a FAT time/date pair. */
void exfat_time_unix2fat(struct exfat_sb_info *sbi, struct timespec_compat *ts,
DATE_TIME_T *tp)
u16 exfat_calc_chksum16(void *data, int len, u16 chksum, int type)
{
time_t second = ts->tv_sec;
time_t day, month, year;
time_t ld; /* leap day */
if (!sbi->options.tz_utc)
second -= sys_tz.tz_minuteswest * SECS_PER_MIN;
/* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
if (second < UNIX_SECS_1980) {
tp->Second = 0;
tp->Minute = 0;
tp->Hour = 0;
tp->Day = 1;
tp->Month = 1;
tp->Year = 0;
return;
}
#if (BITS_PER_LONG == 64)
if (second >= UNIX_SECS_2108) {
tp->Second = 59;
tp->Minute = 59;
tp->Hour = 23;
tp->Day = 31;
tp->Month = 12;
tp->Year = 127;
return;
}
#endif
day = second / SECS_PER_DAY - DAYS_DELTA_DECADE;
year = day / 365;
MAKE_LEAP_YEAR(ld, year);
if (year * 365 + ld > day)
year--;
MAKE_LEAP_YEAR(ld, year);
day -= year * 365 + ld;
if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) {
month = 2;
} else {
if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3])
day--;
for (month = 1; month < 12; month++) {
if (accum_days_in_year[month + 1] > day)
break;
}
}
day -= accum_days_in_year[month];
tp->Second = second % SECS_PER_MIN;
tp->Minute = (second / SECS_PER_MIN) % 60;
tp->Hour = (second / SECS_PER_HOUR) % 24;
tp->Day = day + 1;
tp->Month = month;
tp->Year = year;
}
TIMESTAMP_T *exfat_tm_now(struct exfat_sb_info *sbi, TIMESTAMP_T *tp)
{
struct timespec_compat ts;
DATE_TIME_T dt;
KTIME_GET_REAL_TS(&ts);
exfat_time_unix2fat(sbi, &ts, &dt);
tp->year = dt.Year;
tp->mon = dt.Month;
tp->day = dt.Day;
tp->hour = dt.Hour;
tp->min = dt.Minute;
tp->sec = dt.Second;
return tp;
}
u16 exfat_calc_chksum_2byte(void *data, s32 len, u16 chksum, s32 type)
{
s32 i;
u8 *c = (u8 *) data;
int i;
u8 *c = (u8 *)data;
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;
chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + (u16) *c;
chksum = ((chksum << 15) | (chksum >> 1)) + *c;
}
return chksum;
}
#ifdef CONFIG_EXFAT_DBG_MSG
void __exfat_dmsg(int level, const char *fmt, ...)
u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type)
{
va_list args;
int i;
u8 *c = (u8 *)data;
/* should check type */
if (level > EXFAT_MSG_LEVEL)
return;
va_start(args, fmt);
/* fmt already includes KERN_ pacility level */
vprintk(fmt, args);
va_end(args);
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;
}
void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync)
{
set_bit(EXFAT_SB_DIRTY, &EXFAT_SB(sb)->s_state);
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
if (sync)
sync_dirty_buffer(bh);
}
void exfat_chain_set(struct exfat_chain *ec, unsigned int dir,
unsigned int size, unsigned char flags)
{
ec->dir = dir;
ec->size = size;
ec->flags = flags;
}
void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec)
{
return exfat_chain_set(dup, ec->dir, ec->size, ec->flags);
}
#endif

1450
fs/exfat/namei.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,391 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*
* nls.c: exFAT NLS manager
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#include <linux/string.h>
#include <linux/nls.h>
#include <linux/slab.h>
#include <linux/buffer_head.h>
#include <asm/unaligned.h>
#include "exfat.h"
#include "core.h"
#include "exfat_fs.h"
/* Upcase tabel macro */
#define EXFAT_NUM_UPCASE (2918)
#define UTBL_COUNT (0x10000)
/*
* Upcase table in compressed format (7.2.5.1 Recommended Up-case Table
* in exfat specification, See:
* https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification).
*/
static const unsigned short uni_def_upcase[EXFAT_NUM_UPCASE] = {
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
0x0058, 0x0059, 0x005a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00f7,
0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x0178,
0x0100, 0x0100, 0x0102, 0x0102, 0x0104, 0x0104, 0x0106, 0x0106,
0x0108, 0x0108, 0x010a, 0x010a, 0x010c, 0x010c, 0x010e, 0x010e,
0x0110, 0x0110, 0x0112, 0x0112, 0x0114, 0x0114, 0x0116, 0x0116,
0x0118, 0x0118, 0x011a, 0x011a, 0x011c, 0x011c, 0x011e, 0x011e,
0x0120, 0x0120, 0x0122, 0x0122, 0x0124, 0x0124, 0x0126, 0x0126,
0x0128, 0x0128, 0x012a, 0x012a, 0x012c, 0x012c, 0x012e, 0x012e,
0x0130, 0x0131, 0x0132, 0x0132, 0x0134, 0x0134, 0x0136, 0x0136,
0x0138, 0x0139, 0x0139, 0x013b, 0x013b, 0x013d, 0x013d, 0x013f,
0x013f, 0x0141, 0x0141, 0x0143, 0x0143, 0x0145, 0x0145, 0x0147,
0x0147, 0x0149, 0x014a, 0x014a, 0x014c, 0x014c, 0x014e, 0x014e,
0x0150, 0x0150, 0x0152, 0x0152, 0x0154, 0x0154, 0x0156, 0x0156,
0x0158, 0x0158, 0x015a, 0x015a, 0x015c, 0x015c, 0x015e, 0x015e,
0x0160, 0x0160, 0x0162, 0x0162, 0x0164, 0x0164, 0x0166, 0x0166,
0x0168, 0x0168, 0x016a, 0x016a, 0x016c, 0x016c, 0x016e, 0x016e,
0x0170, 0x0170, 0x0172, 0x0172, 0x0174, 0x0174, 0x0176, 0x0176,
0x0178, 0x0179, 0x0179, 0x017b, 0x017b, 0x017d, 0x017d, 0x017f,
0x0243, 0x0181, 0x0182, 0x0182, 0x0184, 0x0184, 0x0186, 0x0187,
0x0187, 0x0189, 0x018a, 0x018b, 0x018b, 0x018d, 0x018e, 0x018f,
0x0190, 0x0191, 0x0191, 0x0193, 0x0194, 0x01f6, 0x0196, 0x0197,
0x0198, 0x0198, 0x023d, 0x019b, 0x019c, 0x019d, 0x0220, 0x019f,
0x01a0, 0x01a0, 0x01a2, 0x01a2, 0x01a4, 0x01a4, 0x01a6, 0x01a7,
0x01a7, 0x01a9, 0x01aa, 0x01ab, 0x01ac, 0x01ac, 0x01ae, 0x01af,
0x01af, 0x01b1, 0x01b2, 0x01b3, 0x01b3, 0x01b5, 0x01b5, 0x01b7,
0x01b8, 0x01b8, 0x01ba, 0x01bb, 0x01bc, 0x01bc, 0x01be, 0x01f7,
0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c4, 0x01c5, 0x01c4, 0x01c7,
0x01c8, 0x01c7, 0x01ca, 0x01cb, 0x01ca, 0x01cd, 0x01cd, 0x01cf,
0x01cf, 0x01d1, 0x01d1, 0x01d3, 0x01d3, 0x01d5, 0x01d5, 0x01d7,
0x01d7, 0x01d9, 0x01d9, 0x01db, 0x01db, 0x018e, 0x01de, 0x01de,
0x01e0, 0x01e0, 0x01e2, 0x01e2, 0x01e4, 0x01e4, 0x01e6, 0x01e6,
0x01e8, 0x01e8, 0x01ea, 0x01ea, 0x01ec, 0x01ec, 0x01ee, 0x01ee,
0x01f0, 0x01f1, 0x01f2, 0x01f1, 0x01f4, 0x01f4, 0x01f6, 0x01f7,
0x01f8, 0x01f8, 0x01fa, 0x01fa, 0x01fc, 0x01fc, 0x01fe, 0x01fe,
0x0200, 0x0200, 0x0202, 0x0202, 0x0204, 0x0204, 0x0206, 0x0206,
0x0208, 0x0208, 0x020a, 0x020a, 0x020c, 0x020c, 0x020e, 0x020e,
0x0210, 0x0210, 0x0212, 0x0212, 0x0214, 0x0214, 0x0216, 0x0216,
0x0218, 0x0218, 0x021a, 0x021a, 0x021c, 0x021c, 0x021e, 0x021e,
0x0220, 0x0221, 0x0222, 0x0222, 0x0224, 0x0224, 0x0226, 0x0226,
0x0228, 0x0228, 0x022a, 0x022a, 0x022c, 0x022c, 0x022e, 0x022e,
0x0230, 0x0230, 0x0232, 0x0232, 0x0234, 0x0235, 0x0236, 0x0237,
0x0238, 0x0239, 0x2c65, 0x023b, 0x023b, 0x023d, 0x2c66, 0x023f,
0x0240, 0x0241, 0x0241, 0x0243, 0x0244, 0x0245, 0x0246, 0x0246,
0x0248, 0x0248, 0x024a, 0x024a, 0x024c, 0x024c, 0x024e, 0x024e,
0x0250, 0x0251, 0x0252, 0x0181, 0x0186, 0x0255, 0x0189, 0x018a,
0x0258, 0x018f, 0x025a, 0x0190, 0x025c, 0x025d, 0x025e, 0x025f,
0x0193, 0x0261, 0x0262, 0x0194, 0x0264, 0x0265, 0x0266, 0x0267,
0x0197, 0x0196, 0x026a, 0x2c62, 0x026c, 0x026d, 0x026e, 0x019c,
0x0270, 0x0271, 0x019d, 0x0273, 0x0274, 0x019f, 0x0276, 0x0277,
0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x2c64, 0x027e, 0x027f,
0x01a6, 0x0281, 0x0282, 0x01a9, 0x0284, 0x0285, 0x0286, 0x0287,
0x01ae, 0x0244, 0x01b1, 0x01b2, 0x0245, 0x028d, 0x028e, 0x028f,
0x0290, 0x0291, 0x01b7, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297,
0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f,
0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7,
0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af,
0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7,
0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf,
0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7,
0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf,
0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7,
0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df,
0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7,
0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef,
0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7,
0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff,
0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f,
0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f,
0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327,
0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f,
0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337,
0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f,
0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347,
0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f,
0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357,
0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f,
0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367,
0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f,
0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377,
0x0378, 0x0379, 0x037a, 0x03fd, 0x03fe, 0x03ff, 0x037e, 0x037f,
0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387,
0x0388, 0x0389, 0x038a, 0x038b, 0x038c, 0x038d, 0x038e, 0x038f,
0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x0386, 0x0388, 0x0389, 0x038a,
0x03b0, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
0x03a0, 0x03a1, 0x03a3, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x038c, 0x038e, 0x038f, 0x03cf,
0x03d0, 0x03d1, 0x03d2, 0x03d3, 0x03d4, 0x03d5, 0x03d6, 0x03d7,
0x03d8, 0x03d8, 0x03da, 0x03da, 0x03dc, 0x03dc, 0x03de, 0x03de,
0x03e0, 0x03e0, 0x03e2, 0x03e2, 0x03e4, 0x03e4, 0x03e6, 0x03e6,
0x03e8, 0x03e8, 0x03ea, 0x03ea, 0x03ec, 0x03ec, 0x03ee, 0x03ee,
0x03f0, 0x03f1, 0x03f9, 0x03f3, 0x03f4, 0x03f5, 0x03f6, 0x03f7,
0x03f7, 0x03f9, 0x03fa, 0x03fa, 0x03fc, 0x03fd, 0x03fe, 0x03ff,
0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,
0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f,
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,
0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f,
0x0460, 0x0460, 0x0462, 0x0462, 0x0464, 0x0464, 0x0466, 0x0466,
0x0468, 0x0468, 0x046a, 0x046a, 0x046c, 0x046c, 0x046e, 0x046e,
0x0470, 0x0470, 0x0472, 0x0472, 0x0474, 0x0474, 0x0476, 0x0476,
0x0478, 0x0478, 0x047a, 0x047a, 0x047c, 0x047c, 0x047e, 0x047e,
0x0480, 0x0480, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,
0x0488, 0x0489, 0x048a, 0x048a, 0x048c, 0x048c, 0x048e, 0x048e,
0x0490, 0x0490, 0x0492, 0x0492, 0x0494, 0x0494, 0x0496, 0x0496,
0x0498, 0x0498, 0x049a, 0x049a, 0x049c, 0x049c, 0x049e, 0x049e,
0x04a0, 0x04a0, 0x04a2, 0x04a2, 0x04a4, 0x04a4, 0x04a6, 0x04a6,
0x04a8, 0x04a8, 0x04aa, 0x04aa, 0x04ac, 0x04ac, 0x04ae, 0x04ae,
0x04b0, 0x04b0, 0x04b2, 0x04b2, 0x04b4, 0x04b4, 0x04b6, 0x04b6,
0x04b8, 0x04b8, 0x04ba, 0x04ba, 0x04bc, 0x04bc, 0x04be, 0x04be,
0x04c0, 0x04c1, 0x04c1, 0x04c3, 0x04c3, 0x04c5, 0x04c5, 0x04c7,
0x04c7, 0x04c9, 0x04c9, 0x04cb, 0x04cb, 0x04cd, 0x04cd, 0x04c0,
0x04d0, 0x04d0, 0x04d2, 0x04d2, 0x04d4, 0x04d4, 0x04d6, 0x04d6,
0x04d8, 0x04d8, 0x04da, 0x04da, 0x04dc, 0x04dc, 0x04de, 0x04de,
0x04e0, 0x04e0, 0x04e2, 0x04e2, 0x04e4, 0x04e4, 0x04e6, 0x04e6,
0x04e8, 0x04e8, 0x04ea, 0x04ea, 0x04ec, 0x04ec, 0x04ee, 0x04ee,
0x04f0, 0x04f0, 0x04f2, 0x04f2, 0x04f4, 0x04f4, 0x04f6, 0x04f6,
0x04f8, 0x04f8, 0x04fa, 0x04fa, 0x04fc, 0x04fc, 0x04fe, 0x04fe,
0x0500, 0x0500, 0x0502, 0x0502, 0x0504, 0x0504, 0x0506, 0x0506,
0x0508, 0x0508, 0x050a, 0x050a, 0x050c, 0x050c, 0x050e, 0x050e,
0x0510, 0x0510, 0x0512, 0x0512, 0x0514, 0x0515, 0x0516, 0x0517,
0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f,
0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527,
0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f,
0x0530, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537,
0x0538, 0x0539, 0x053a, 0x053b, 0x053c, 0x053d, 0x053e, 0x053f,
0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547,
0x0548, 0x0549, 0x054a, 0x054b, 0x054c, 0x054d, 0x054e, 0x054f,
0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0x0557,
0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f,
0x0560, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537,
0x0538, 0x0539, 0x053a, 0x053b, 0x053c, 0x053d, 0x053e, 0x053f,
0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547,
0x0548, 0x0549, 0x054a, 0x054b, 0x054c, 0x054d, 0x054e, 0x054f,
0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0xffff,
0x17f6, 0x2c63, 0x1d7e, 0x1d7f, 0x1d80, 0x1d81, 0x1d82, 0x1d83,
0x1d84, 0x1d85, 0x1d86, 0x1d87, 0x1d88, 0x1d89, 0x1d8a, 0x1d8b,
0x1d8c, 0x1d8d, 0x1d8e, 0x1d8f, 0x1d90, 0x1d91, 0x1d92, 0x1d93,
0x1d94, 0x1d95, 0x1d96, 0x1d97, 0x1d98, 0x1d99, 0x1d9a, 0x1d9b,
0x1d9c, 0x1d9d, 0x1d9e, 0x1d9f, 0x1da0, 0x1da1, 0x1da2, 0x1da3,
0x1da4, 0x1da5, 0x1da6, 0x1da7, 0x1da8, 0x1da9, 0x1daa, 0x1dab,
0x1dac, 0x1dad, 0x1dae, 0x1daf, 0x1db0, 0x1db1, 0x1db2, 0x1db3,
0x1db4, 0x1db5, 0x1db6, 0x1db7, 0x1db8, 0x1db9, 0x1dba, 0x1dbb,
0x1dbc, 0x1dbd, 0x1dbe, 0x1dbf, 0x1dc0, 0x1dc1, 0x1dc2, 0x1dc3,
0x1dc4, 0x1dc5, 0x1dc6, 0x1dc7, 0x1dc8, 0x1dc9, 0x1dca, 0x1dcb,
0x1dcc, 0x1dcd, 0x1dce, 0x1dcf, 0x1dd0, 0x1dd1, 0x1dd2, 0x1dd3,
0x1dd4, 0x1dd5, 0x1dd6, 0x1dd7, 0x1dd8, 0x1dd9, 0x1dda, 0x1ddb,
0x1ddc, 0x1ddd, 0x1dde, 0x1ddf, 0x1de0, 0x1de1, 0x1de2, 0x1de3,
0x1de4, 0x1de5, 0x1de6, 0x1de7, 0x1de8, 0x1de9, 0x1dea, 0x1deb,
0x1dec, 0x1ded, 0x1dee, 0x1def, 0x1df0, 0x1df1, 0x1df2, 0x1df3,
0x1df4, 0x1df5, 0x1df6, 0x1df7, 0x1df8, 0x1df9, 0x1dfa, 0x1dfb,
0x1dfc, 0x1dfd, 0x1dfe, 0x1dff, 0x1e00, 0x1e00, 0x1e02, 0x1e02,
0x1e04, 0x1e04, 0x1e06, 0x1e06, 0x1e08, 0x1e08, 0x1e0a, 0x1e0a,
0x1e0c, 0x1e0c, 0x1e0e, 0x1e0e, 0x1e10, 0x1e10, 0x1e12, 0x1e12,
0x1e14, 0x1e14, 0x1e16, 0x1e16, 0x1e18, 0x1e18, 0x1e1a, 0x1e1a,
0x1e1c, 0x1e1c, 0x1e1e, 0x1e1e, 0x1e20, 0x1e20, 0x1e22, 0x1e22,
0x1e24, 0x1e24, 0x1e26, 0x1e26, 0x1e28, 0x1e28, 0x1e2a, 0x1e2a,
0x1e2c, 0x1e2c, 0x1e2e, 0x1e2e, 0x1e30, 0x1e30, 0x1e32, 0x1e32,
0x1e34, 0x1e34, 0x1e36, 0x1e36, 0x1e38, 0x1e38, 0x1e3a, 0x1e3a,
0x1e3c, 0x1e3c, 0x1e3e, 0x1e3e, 0x1e40, 0x1e40, 0x1e42, 0x1e42,
0x1e44, 0x1e44, 0x1e46, 0x1e46, 0x1e48, 0x1e48, 0x1e4a, 0x1e4a,
0x1e4c, 0x1e4c, 0x1e4e, 0x1e4e, 0x1e50, 0x1e50, 0x1e52, 0x1e52,
0x1e54, 0x1e54, 0x1e56, 0x1e56, 0x1e58, 0x1e58, 0x1e5a, 0x1e5a,
0x1e5c, 0x1e5c, 0x1e5e, 0x1e5e, 0x1e60, 0x1e60, 0x1e62, 0x1e62,
0x1e64, 0x1e64, 0x1e66, 0x1e66, 0x1e68, 0x1e68, 0x1e6a, 0x1e6a,
0x1e6c, 0x1e6c, 0x1e6e, 0x1e6e, 0x1e70, 0x1e70, 0x1e72, 0x1e72,
0x1e74, 0x1e74, 0x1e76, 0x1e76, 0x1e78, 0x1e78, 0x1e7a, 0x1e7a,
0x1e7c, 0x1e7c, 0x1e7e, 0x1e7e, 0x1e80, 0x1e80, 0x1e82, 0x1e82,
0x1e84, 0x1e84, 0x1e86, 0x1e86, 0x1e88, 0x1e88, 0x1e8a, 0x1e8a,
0x1e8c, 0x1e8c, 0x1e8e, 0x1e8e, 0x1e90, 0x1e90, 0x1e92, 0x1e92,
0x1e94, 0x1e94, 0x1e96, 0x1e97, 0x1e98, 0x1e99, 0x1e9a, 0x1e9b,
0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f, 0x1ea0, 0x1ea0, 0x1ea2, 0x1ea2,
0x1ea4, 0x1ea4, 0x1ea6, 0x1ea6, 0x1ea8, 0x1ea8, 0x1eaa, 0x1eaa,
0x1eac, 0x1eac, 0x1eae, 0x1eae, 0x1eb0, 0x1eb0, 0x1eb2, 0x1eb2,
0x1eb4, 0x1eb4, 0x1eb6, 0x1eb6, 0x1eb8, 0x1eb8, 0x1eba, 0x1eba,
0x1ebc, 0x1ebc, 0x1ebe, 0x1ebe, 0x1ec0, 0x1ec0, 0x1ec2, 0x1ec2,
0x1ec4, 0x1ec4, 0x1ec6, 0x1ec6, 0x1ec8, 0x1ec8, 0x1eca, 0x1eca,
0x1ecc, 0x1ecc, 0x1ece, 0x1ece, 0x1ed0, 0x1ed0, 0x1ed2, 0x1ed2,
0x1ed4, 0x1ed4, 0x1ed6, 0x1ed6, 0x1ed8, 0x1ed8, 0x1eda, 0x1eda,
0x1edc, 0x1edc, 0x1ede, 0x1ede, 0x1ee0, 0x1ee0, 0x1ee2, 0x1ee2,
0x1ee4, 0x1ee4, 0x1ee6, 0x1ee6, 0x1ee8, 0x1ee8, 0x1eea, 0x1eea,
0x1eec, 0x1eec, 0x1eee, 0x1eee, 0x1ef0, 0x1ef0, 0x1ef2, 0x1ef2,
0x1ef4, 0x1ef4, 0x1ef6, 0x1ef6, 0x1ef8, 0x1ef8, 0x1efa, 0x1efb,
0x1efc, 0x1efd, 0x1efe, 0x1eff, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b,
0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b,
0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b,
0x1f1c, 0x1f1d, 0x1f16, 0x1f17, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b,
0x1f1c, 0x1f1d, 0x1f1e, 0x1f1f, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b,
0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b,
0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b,
0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b,
0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b,
0x1f4c, 0x1f4d, 0x1f46, 0x1f47, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b,
0x1f4c, 0x1f4d, 0x1f4e, 0x1f4f, 0x1f50, 0x1f59, 0x1f52, 0x1f5b,
0x1f54, 0x1f5d, 0x1f56, 0x1f5f, 0x1f58, 0x1f59, 0x1f5a, 0x1f5b,
0x1f5c, 0x1f5d, 0x1f5e, 0x1f5f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b,
0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b,
0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1fba, 0x1fbb, 0x1fc8, 0x1fc9,
0x1fca, 0x1fcb, 0x1fda, 0x1fdb, 0x1ff8, 0x1ff9, 0x1fea, 0x1feb,
0x1ffa, 0x1ffb, 0x1f7e, 0x1f7f, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b,
0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f88, 0x1f89, 0x1f8a, 0x1f8b,
0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b,
0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1f98, 0x1f99, 0x1f9a, 0x1f9b,
0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab,
0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fa8, 0x1fa9, 0x1faa, 0x1fab,
0x1fac, 0x1fad, 0x1fae, 0x1faf, 0x1fb8, 0x1fb9, 0x1fb2, 0x1fbc,
0x1fb4, 0x1fb5, 0x1fb6, 0x1fb7, 0x1fb8, 0x1fb9, 0x1fba, 0x1fbb,
0x1fbc, 0x1fbd, 0x1fbe, 0x1fbf, 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3,
0x1fc4, 0x1fc5, 0x1fc6, 0x1fc7, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb,
0x1fc3, 0x1fcd, 0x1fce, 0x1fcf, 0x1fd8, 0x1fd9, 0x1fd2, 0x1fd3,
0x1fd4, 0x1fd5, 0x1fd6, 0x1fd7, 0x1fd8, 0x1fd9, 0x1fda, 0x1fdb,
0x1fdc, 0x1fdd, 0x1fde, 0x1fdf, 0x1fe8, 0x1fe9, 0x1fe2, 0x1fe3,
0x1fe4, 0x1fec, 0x1fe6, 0x1fe7, 0x1fe8, 0x1fe9, 0x1fea, 0x1feb,
0x1fec, 0x1fed, 0x1fee, 0x1fef, 0x1ff0, 0x1ff1, 0x1ff2, 0x1ff3,
0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7, 0x1ff8, 0x1ff9, 0x1ffa, 0x1ffb,
0x1ff3, 0x1ffd, 0x1ffe, 0x1fff, 0x2000, 0x2001, 0x2002, 0x2003,
0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, 0x200b,
0x200c, 0x200d, 0x200e, 0x200f, 0x2010, 0x2011, 0x2012, 0x2013,
0x2014, 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201a, 0x201b,
0x201c, 0x201d, 0x201e, 0x201f, 0x2020, 0x2021, 0x2022, 0x2023,
0x2024, 0x2025, 0x2026, 0x2027, 0x2028, 0x2029, 0x202a, 0x202b,
0x202c, 0x202d, 0x202e, 0x202f, 0x2030, 0x2031, 0x2032, 0x2033,
0x2034, 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203a, 0x203b,
0x203c, 0x203d, 0x203e, 0x203f, 0x2040, 0x2041, 0x2042, 0x2043,
0x2044, 0x2045, 0x2046, 0x2047, 0x2048, 0x2049, 0x204a, 0x204b,
0x204c, 0x204d, 0x204e, 0x204f, 0x2050, 0x2051, 0x2052, 0x2053,
0x2054, 0x2055, 0x2056, 0x2057, 0x2058, 0x2059, 0x205a, 0x205b,
0x205c, 0x205d, 0x205e, 0x205f, 0x2060, 0x2061, 0x2062, 0x2063,
0x2064, 0x2065, 0x2066, 0x2067, 0x2068, 0x2069, 0x206a, 0x206b,
0x206c, 0x206d, 0x206e, 0x206f, 0x2070, 0x2071, 0x2072, 0x2073,
0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207a, 0x207b,
0x207c, 0x207d, 0x207e, 0x207f, 0x2080, 0x2081, 0x2082, 0x2083,
0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208a, 0x208b,
0x208c, 0x208d, 0x208e, 0x208f, 0x2090, 0x2091, 0x2092, 0x2093,
0x2094, 0x2095, 0x2096, 0x2097, 0x2098, 0x2099, 0x209a, 0x209b,
0x209c, 0x209d, 0x209e, 0x209f, 0x20a0, 0x20a1, 0x20a2, 0x20a3,
0x20a4, 0x20a5, 0x20a6, 0x20a7, 0x20a8, 0x20a9, 0x20aa, 0x20ab,
0x20ac, 0x20ad, 0x20ae, 0x20af, 0x20b0, 0x20b1, 0x20b2, 0x20b3,
0x20b4, 0x20b5, 0x20b6, 0x20b7, 0x20b8, 0x20b9, 0x20ba, 0x20bb,
0x20bc, 0x20bd, 0x20be, 0x20bf, 0x20c0, 0x20c1, 0x20c2, 0x20c3,
0x20c4, 0x20c5, 0x20c6, 0x20c7, 0x20c8, 0x20c9, 0x20ca, 0x20cb,
0x20cc, 0x20cd, 0x20ce, 0x20cf, 0x20d0, 0x20d1, 0x20d2, 0x20d3,
0x20d4, 0x20d5, 0x20d6, 0x20d7, 0x20d8, 0x20d9, 0x20da, 0x20db,
0x20dc, 0x20dd, 0x20de, 0x20df, 0x20e0, 0x20e1, 0x20e2, 0x20e3,
0x20e4, 0x20e5, 0x20e6, 0x20e7, 0x20e8, 0x20e9, 0x20ea, 0x20eb,
0x20ec, 0x20ed, 0x20ee, 0x20ef, 0x20f0, 0x20f1, 0x20f2, 0x20f3,
0x20f4, 0x20f5, 0x20f6, 0x20f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb,
0x20fc, 0x20fd, 0x20fe, 0x20ff, 0x2100, 0x2101, 0x2102, 0x2103,
0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210a, 0x210b,
0x210c, 0x210d, 0x210e, 0x210f, 0x2110, 0x2111, 0x2112, 0x2113,
0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211a, 0x211b,
0x211c, 0x211d, 0x211e, 0x211f, 0x2120, 0x2121, 0x2122, 0x2123,
0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212a, 0x212b,
0x212c, 0x212d, 0x212e, 0x212f, 0x2130, 0x2131, 0x2132, 0x2133,
0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213a, 0x213b,
0x213c, 0x213d, 0x213e, 0x213f, 0x2140, 0x2141, 0x2142, 0x2143,
0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214a, 0x214b,
0x214c, 0x214d, 0x2132, 0x214f, 0x2150, 0x2151, 0x2152, 0x2153,
0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, 0x215b,
0x215c, 0x215d, 0x215e, 0x215f, 0x2160, 0x2161, 0x2162, 0x2163,
0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b,
0x216c, 0x216d, 0x216e, 0x216f, 0x2160, 0x2161, 0x2162, 0x2163,
0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216a, 0x216b,
0x216c, 0x216d, 0x216e, 0x216f, 0x2180, 0x2181, 0x2182, 0x2183,
0x2183, 0xffff, 0x034b, 0x24b6, 0x24b7, 0x24b8, 0x24b9, 0x24ba,
0x24bb, 0x24bc, 0x24bd, 0x24be, 0x24bf, 0x24c0, 0x24c1, 0x24c2,
0x24c3, 0x24c4, 0x24c5, 0x24c6, 0x24c7, 0x24c8, 0x24c9, 0x24ca,
0x24cb, 0x24cc, 0x24cd, 0x24ce, 0x24cf, 0xffff, 0x0746, 0x2c00,
0x2c01, 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x2c08,
0x2c09, 0x2c0a, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x2c10,
0x2c11, 0x2c12, 0x2c13, 0x2c14, 0x2c15, 0x2c16, 0x2c17, 0x2c18,
0x2c19, 0x2c1a, 0x2c1b, 0x2c1c, 0x2c1d, 0x2c1e, 0x2c1f, 0x2c20,
0x2c21, 0x2c22, 0x2c23, 0x2c24, 0x2c25, 0x2c26, 0x2c27, 0x2c28,
0x2c29, 0x2c2a, 0x2c2b, 0x2c2c, 0x2c2d, 0x2c2e, 0x2c5f, 0x2c60,
0x2c60, 0x2c62, 0x2c63, 0x2c64, 0x2c65, 0x2c66, 0x2c67, 0x2c67,
0x2c69, 0x2c69, 0x2c6b, 0x2c6b, 0x2c6d, 0x2c6e, 0x2c6f, 0x2c70,
0x2c71, 0x2c72, 0x2c73, 0x2c74, 0x2c75, 0x2c75, 0x2c77, 0x2c78,
0x2c79, 0x2c7a, 0x2c7b, 0x2c7c, 0x2c7d, 0x2c7e, 0x2c7f, 0x2c80,
0x2c80, 0x2c82, 0x2c82, 0x2c84, 0x2c84, 0x2c86, 0x2c86, 0x2c88,
0x2c88, 0x2c8a, 0x2c8a, 0x2c8c, 0x2c8c, 0x2c8e, 0x2c8e, 0x2c90,
0x2c90, 0x2c92, 0x2c92, 0x2c94, 0x2c94, 0x2c96, 0x2c96, 0x2c98,
0x2c98, 0x2c9a, 0x2c9a, 0x2c9c, 0x2c9c, 0x2c9e, 0x2c9e, 0x2ca0,
0x2ca0, 0x2ca2, 0x2ca2, 0x2ca4, 0x2ca4, 0x2ca6, 0x2ca6, 0x2ca8,
0x2ca8, 0x2caa, 0x2caa, 0x2cac, 0x2cac, 0x2cae, 0x2cae, 0x2cb0,
0x2cb0, 0x2cb2, 0x2cb2, 0x2cb4, 0x2cb4, 0x2cb6, 0x2cb6, 0x2cb8,
0x2cb8, 0x2cba, 0x2cba, 0x2cbc, 0x2cbc, 0x2cbe, 0x2cbe, 0x2cc0,
0x2cc0, 0x2cc2, 0x2cc2, 0x2cc4, 0x2cc4, 0x2cc6, 0x2cc6, 0x2cc8,
0x2cc8, 0x2cca, 0x2cca, 0x2ccc, 0x2ccc, 0x2cce, 0x2cce, 0x2cd0,
0x2cd0, 0x2cd2, 0x2cd2, 0x2cd4, 0x2cd4, 0x2cd6, 0x2cd6, 0x2cd8,
0x2cd8, 0x2cda, 0x2cda, 0x2cdc, 0x2cdc, 0x2cde, 0x2cde, 0x2ce0,
0x2ce0, 0x2ce2, 0x2ce2, 0x2ce4, 0x2ce5, 0x2ce6, 0x2ce7, 0x2ce8,
0x2ce9, 0x2cea, 0x2ceb, 0x2cec, 0x2ced, 0x2cee, 0x2cef, 0x2cf0,
0x2cf1, 0x2cf2, 0x2cf3, 0x2cf4, 0x2cf5, 0x2cf6, 0x2cf7, 0x2cf8,
0x2cf9, 0x2cfa, 0x2cfb, 0x2cfc, 0x2cfd, 0x2cfe, 0x2cff, 0x10a0,
0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, 0x10a8,
0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, 0x10b0,
0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7, 0x10b8,
0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf, 0x10c0,
0x10c1, 0x10c2, 0x10c3, 0x10c4, 0x10c5, 0xffff, 0xd21b, 0xff21,
0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, 0xff28, 0xff29,
0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, 0xff31,
0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39,
0xff3a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f, 0xff60, 0xff61,
0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67, 0xff68, 0xff69,
0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f, 0xff70, 0xff71,
0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77, 0xff78, 0xff79,
0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f, 0xff80, 0xff81,
0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87, 0xff88, 0xff89,
0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f, 0xff90, 0xff91,
0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97, 0xff98, 0xff99,
0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f, 0xffa0, 0xffa1,
0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7, 0xffa8, 0xffa9,
0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf, 0xffb0, 0xffb1,
0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7, 0xffb8, 0xffb9,
0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf, 0xffc0, 0xffc1,
0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, 0xffc8, 0xffc9,
0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf, 0xffd0, 0xffd1,
0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7, 0xffd8, 0xffd9,
0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf, 0xffe0, 0xffe1,
0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7, 0xffe8, 0xffe9,
0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef, 0xfff0, 0xfff1,
0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7, 0xfff8, 0xfff9,
0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff,
};
/*
* Allow full-width illegal characters :
@ -18,120 +394,93 @@
* for compatibility.
*
* " * / : < > ? \ |
*
* patch 1.2.0
*/
static u16 bad_uni_chars[] = {
static unsigned short bad_uni_chars[] = {
0x0022, 0x002A, 0x002F, 0x003A,
0x003C, 0x003E, 0x003F, 0x005C, 0x007C,
#if 0 /* allow full-width characters */
0x201C, 0x201D, 0xFF0A, 0xFF0F, 0xFF1A,
0xFF1C, 0xFF1E, 0xFF1F, 0xFF3C, 0xFF5C,
#endif
0
};
static s32 convert_uni_to_ch(struct nls_table *nls, u16 uni, u8 *ch, s32 *lossy);
static s32 convert_ch_to_uni(struct nls_table *nls, u8 *ch, u16 *uni, s32 *lossy);
static u16 nls_upper(struct super_block *sb, u16 a)
static int exfat_convert_char_to_ucs2(struct nls_table *nls,
const unsigned char *ch, int ch_len, unsigned short *ucs2,
int *lossy)
{
FS_INFO_T *fsi = &(EXFAT_SB(sb)->fsi);
int len;
if (EXFAT_SB(sb)->options.casesensitive)
return a;
if ((fsi->vol_utbl)[exfat_get_col_index(a)] != NULL)
return (fsi->vol_utbl)[exfat_get_col_index(a)][exfat_get_row_index(a)];
else
return a;
*ucs2 = 0x0;
if (ch[0] < 0x80) {
*ucs2 = ch[0];
return 1;
}
len = nls->char2uni(ch, ch_len, ucs2);
if (len < 0) {
/* conversion failed */
if (lossy != NULL)
*lossy |= NLS_NAME_LOSSY;
*ucs2 = '_';
return 1;
}
return len;
}
u16 *nls_wstrchr(u16 *str, u16 wchar)
static int exfat_convert_ucs2_to_char(struct nls_table *nls,
unsigned short ucs2, unsigned char *ch, int *lossy)
{
int len;
ch[0] = 0x0;
if (ucs2 < 0x0080) {
ch[0] = ucs2;
return 1;
}
len = nls->uni2char(ucs2, ch, MAX_CHARSET_SIZE);
if (len < 0) {
/* conversion failed */
if (lossy != NULL)
*lossy |= NLS_NAME_LOSSY;
ch[0] = '_';
return 1;
}
return len;
}
unsigned short exfat_toupper(struct super_block *sb, unsigned short a)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
return sbi->vol_utbl[a] ? sbi->vol_utbl[a] : a;
}
static unsigned short *exfat_wstrchr(unsigned short *str, unsigned short wchar)
{
while (*str) {
if (*(str++) == wchar)
return str;
}
return 0;
return NULL;
}
s32 exfat_nls_cmp_uniname(struct super_block *sb, u16 *a, u16 *b)
int exfat_uniname_ncmp(struct super_block *sb, unsigned short *a,
unsigned short *b, unsigned int len)
{
s32 i;
int i;
for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) {
if (nls_upper(sb, *a) != nls_upper(sb, *b))
for (i = 0; i < len; i++, a++, b++)
if (exfat_toupper(sb, *a) != exfat_toupper(sb, *b))
return 1;
if (*a == 0x0)
return 0;
}
return 0;
}
#define CASE_LOWER_BASE (0x08) /* base is lower case */
#define CASE_LOWER_EXT (0x10) /* extension is lower case */
s32 exfat_nls_sfn_to_uni16s(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname)
static int exfat_utf16_to_utf8(struct super_block *sb,
struct exfat_uni_name *p_uniname, unsigned char *p_cstring,
int buflen)
{
s32 i = 0, j, n = 0;
u8 buf[MAX_DOSNAME_BUF_SIZE];
u8 *dosname = p_dosname->name;
u16 *uniname = p_uniname->name;
struct nls_table *nls = EXFAT_SB(sb)->nls_disk;
if (*dosname == 0x05) {
*buf = 0xE5;
i++;
n++;
}
for ( ; i < 8; i++, n++) {
if (*(dosname+i) == ' ')
break;
if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') &&
(p_dosname->name_case & CASE_LOWER_BASE))
*(buf+n) = *(dosname+i) + ('a' - 'A');
else
*(buf+n) = *(dosname+i);
}
if (*(dosname+8) != ' ') {
*(buf+n) = '.';
n++;
}
for (i = 8; i < DOS_NAME_LENGTH; i++, n++) {
if (*(dosname+i) == ' ')
break;
if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') &&
(p_dosname->name_case & CASE_LOWER_EXT))
*(buf+n) = *(dosname+i) + ('a' - 'A');
else
*(buf+n) = *(dosname+i);
}
*(buf+n) = '\0';
i = j = 0;
while (j < MAX_NAME_LENGTH) {
if (*(buf+i) == '\0')
break;
i += convert_ch_to_uni(nls, (buf+i), uniname, NULL);
uniname++;
j++;
}
*uniname = (u16) '\0';
return j;
}
static s32 __nls_utf16s_to_vfsname(struct super_block *sb, UNI_NAME_T *p_uniname, u8 *p_cstring, s32 buflen)
{
s32 len;
const u16 *uniname = p_uniname->name;
int len;
const unsigned short *uniname = p_uniname->name;
/* always len >= 0 */
len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN,
@ -140,75 +489,98 @@ static s32 __nls_utf16s_to_vfsname(struct super_block *sb, UNI_NAME_T *p_uniname
return len;
}
static s32 __nls_vfsname_to_utf16s(struct super_block *sb, const u8 *p_cstring,
const s32 len, UNI_NAME_T *p_uniname, s32 *p_lossy)
static int exfat_utf8_to_utf16(struct super_block *sb,
const unsigned char *p_cstring, const int len,
struct exfat_uni_name *p_uniname, int *p_lossy)
{
s32 i, unilen, lossy = NLS_NAME_NO_LOSSY;
u16 upname[MAX_NAME_LENGTH+1];
u16 *uniname = p_uniname->name;
int i, unilen, lossy = NLS_NAME_NO_LOSSY;
unsigned short upname[MAX_NAME_LENGTH + 1];
unsigned short *uniname = p_uniname->name;
BUG_ON(!len);
WARN_ON(!len);
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) {
MMSG("%s: failed to vfsname_to_utf16(err:%d) "
"vfsnamelen:%d", __func__, unilen, len);
exfat_err(sb, "failed to %s (err : %d) nls len : %d",
__func__, unilen, len);
return unilen;
}
if (unilen > MAX_NAME_LENGTH) {
MMSG("%s: failed to vfsname_to_utf16(estr:ENAMETOOLONG) "
"vfsnamelen:%d, unilen:%d>%d",
__func__, len, unilen, MAX_NAME_LENGTH);
exfat_err(sb, "failed to %s (estr:ENAMETOOLONG) nls len : %d, unilen : %d > %d",
__func__, len, unilen, MAX_NAME_LENGTH);
return -ENAMETOOLONG;
}
p_uniname->name_len = (u8)(unilen & 0xFF);
for (i = 0; i < unilen; i++) {
if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname))
if (*uniname < 0x0020 ||
exfat_wstrchr(bad_uni_chars, *uniname))
lossy |= NLS_NAME_LOSSY;
*(upname+i) = nls_upper(sb, *uniname);
upname[i] = exfat_toupper(sb, *uniname);
uniname++;
}
*uniname = (u16)'\0';
*uniname = '\0';
p_uniname->name_len = unilen;
p_uniname->name_hash = exfat_calc_chksum_2byte((void *) upname,
unilen << 1, 0, CS_DEFAULT);
p_uniname->name_hash = exfat_calc_chksum16(upname, unilen << 1, 0,
CS_DEFAULT);
if (p_lossy)
*p_lossy = lossy;
return unilen;
}
static s32 __exfat_nls_uni16s_to_vfsname(struct super_block *sb, UNI_NAME_T *p_uniname, u8 *p_cstring, s32 buflen)
#define SURROGATE_MASK 0xfffff800
#define SURROGATE_PAIR 0x0000d800
#define SURROGATE_LOW 0x00000400
static int __exfat_utf16_to_nls(struct super_block *sb,
struct exfat_uni_name *p_uniname, unsigned char *p_cstring,
int buflen)
{
s32 i, j, len, out_len = 0;
u8 buf[MAX_CHARSET_SIZE];
const u16 *uniname = p_uniname->name;
int i, j, len, out_len = 0;
unsigned char buf[MAX_CHARSET_SIZE];
const unsigned short *uniname = p_uniname->name;
struct nls_table *nls = EXFAT_SB(sb)->nls_io;
i = 0;
while ((i < MAX_NAME_LENGTH) && (out_len < (buflen-1))) {
if (*uniname == (u16)'\0')
while (i < MAX_NAME_LENGTH && out_len < (buflen - 1)) {
if (*uniname == '\0')
break;
if ((*uniname & SURROGATE_MASK) != SURROGATE_PAIR) {
len = exfat_convert_ucs2_to_char(nls, *uniname, buf,
NULL);
} else {
/* Process UTF-16 surrogate pair as one character */
if (!(*uniname & SURROGATE_LOW) &&
i+1 < MAX_NAME_LENGTH &&
(*(uniname+1) & SURROGATE_MASK) == SURROGATE_PAIR &&
(*(uniname+1) & SURROGATE_LOW)) {
uniname++;
i++;
}
len = convert_uni_to_ch(nls, *uniname, buf, NULL);
/*
* UTF-16 surrogate pair encodes code points above
* U+FFFF. Code points above U+FFFF are not supported
* by kernel NLS framework therefore use replacement
* character
*/
len = 1;
buf[0] = '_';
}
if (out_len + len >= buflen)
len = (buflen - 1) - out_len;
len = buflen - 1 - out_len;
out_len += len;
if (len > 1) {
for (j = 0; j < len; j++)
*p_cstring++ = (s8) *(buf+j);
*p_cstring++ = buf[j];
} else { /* len == 1 */
*p_cstring++ = (s8) *buf;
*p_cstring++ = *buf;
}
uniname++;
@ -219,105 +591,216 @@ static s32 __exfat_nls_uni16s_to_vfsname(struct super_block *sb, UNI_NAME_T *p_u
return out_len;
}
static s32 __exfat_nls_vfsname_to_uni16s(struct super_block *sb, const u8 *p_cstring,
const s32 len, UNI_NAME_T *p_uniname, s32 *p_lossy)
static int exfat_nls_to_ucs2(struct super_block *sb,
const unsigned char *p_cstring, const int len,
struct exfat_uni_name *p_uniname, int *p_lossy)
{
s32 i, unilen, lossy = NLS_NAME_NO_LOSSY;
u16 upname[MAX_NAME_LENGTH+1];
u16 *uniname = p_uniname->name;
int i = 0, unilen = 0, lossy = NLS_NAME_NO_LOSSY;
unsigned short upname[MAX_NAME_LENGTH + 1];
unsigned short *uniname = p_uniname->name;
struct nls_table *nls = EXFAT_SB(sb)->nls_io;
BUG_ON(!len);
WARN_ON(!len);
i = unilen = 0;
while ((unilen < MAX_NAME_LENGTH) && (i < len)) {
i += convert_ch_to_uni(nls, (u8 *)(p_cstring+i), uniname, &lossy);
while (unilen < MAX_NAME_LENGTH && i < len) {
i += exfat_convert_char_to_ucs2(nls, p_cstring + i, len - i,
uniname, &lossy);
if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname))
if (*uniname < 0x0020 ||
exfat_wstrchr(bad_uni_chars, *uniname))
lossy |= NLS_NAME_LOSSY;
*(upname+unilen) = nls_upper(sb, *uniname);
upname[unilen] = exfat_toupper(sb, *uniname);
uniname++;
unilen++;
}
if (*(p_cstring+i) != '\0')
if (p_cstring[i] != '\0')
lossy |= NLS_NAME_OVERLEN;
*uniname = (u16)'\0';
*uniname = '\0';
p_uniname->name_len = unilen;
p_uniname->name_hash =
exfat_calc_chksum_2byte((void *) upname, unilen<<1, 0, CS_DEFAULT);
p_uniname->name_hash = exfat_calc_chksum16(upname, unilen << 1, 0,
CS_DEFAULT);
if (p_lossy)
*p_lossy = lossy;
return unilen;
}
s32 exfat_nls_uni16s_to_vfsname(struct super_block *sb, UNI_NAME_T *uniname, u8 *p_cstring, s32 buflen)
int exfat_utf16_to_nls(struct super_block *sb, struct exfat_uni_name *uniname,
unsigned char *p_cstring, int buflen)
{
if (EXFAT_SB(sb)->options.utf8)
return __nls_utf16s_to_vfsname(sb, uniname, p_cstring, buflen);
return __exfat_nls_uni16s_to_vfsname(sb, uniname, p_cstring, buflen);
return exfat_utf16_to_utf8(sb, uniname, p_cstring,
buflen);
return __exfat_utf16_to_nls(sb, uniname, p_cstring, buflen);
}
s32 exfat_nls_vfsname_to_uni16s(struct super_block *sb, const u8 *p_cstring, const s32 len, UNI_NAME_T *uniname, s32 *p_lossy)
int exfat_nls_to_utf16(struct super_block *sb, const unsigned char *p_cstring,
const int len, struct exfat_uni_name *uniname, int *p_lossy)
{
if (EXFAT_SB(sb)->options.utf8)
return __nls_vfsname_to_utf16s(sb, p_cstring, len, uniname, p_lossy);
return __exfat_nls_vfsname_to_uni16s(sb, p_cstring, len, uniname, p_lossy);
return exfat_utf8_to_utf16(sb, p_cstring, len,
uniname, p_lossy);
return exfat_nls_to_ucs2(sb, p_cstring, len, uniname, p_lossy);
}
static s32 convert_ch_to_uni(struct nls_table *nls, u8 *ch, u16 *uni, s32 *lossy)
static int exfat_load_upcase_table(struct super_block *sb,
sector_t sector, unsigned long long num_sectors,
unsigned int utbl_checksum)
{
int len;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
unsigned int sect_size = sb->s_blocksize;
unsigned int i, index = 0;
u32 chksum = 0;
int ret;
unsigned char skip = false;
unsigned short *upcase_table;
*uni = 0x0;
upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL);
if (!upcase_table)
return -ENOMEM;
if (ch[0] < 0x80) {
*uni = (u16) ch[0];
return 1;
sbi->vol_utbl = upcase_table;
num_sectors += sector;
while (sector < num_sectors) {
struct buffer_head *bh;
bh = sb_bread(sb, sector);
if (!bh) {
exfat_err(sb, "failed to read sector(0x%llx)\n",
(unsigned long long)sector);
ret = -EIO;
goto free_table;
}
sector++;
for (i = 0; i < sect_size && index <= 0xFFFF; i += 2) {
unsigned short uni = get_unaligned_le16(bh->b_data + i);
if (skip) {
index += uni;
skip = false;
} else if (uni == index) {
index++;
} else if (uni == 0xFFFF) {
skip = true;
} else { /* uni != index , uni != 0xFFFF */
upcase_table[index] = uni;
index++;
}
}
chksum = exfat_calc_chksum32(bh->b_data, i, chksum, CS_DEFAULT);
brelse(bh);
}
len = nls->char2uni(ch, MAX_CHARSET_SIZE, uni);
if (len < 0) {
/* conversion failed */
DMSG("%s: fail to use nls\n", __func__);
if (lossy != NULL)
*lossy |= NLS_NAME_LOSSY;
*uni = (u16) '_';
if (!strcmp(nls->charset, "utf8"))
return 1;
return 2;
}
if (index >= 0xFFFF && utbl_checksum == chksum)
return 0;
return len;
exfat_err(sb, "failed to load upcase table (idx : 0x%08x, chksum : 0x%08x, utbl_chksum : 0x%08x)",
index, chksum, utbl_checksum);
ret = -EINVAL;
free_table:
exfat_free_upcase_table(sbi);
return ret;
}
static s32 convert_uni_to_ch(struct nls_table *nls, u16 uni, u8 *ch, s32 *lossy)
static int exfat_load_default_upcase_table(struct super_block *sb)
{
int len;
int i, ret = -EIO;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
unsigned char skip = false;
unsigned short uni = 0, *upcase_table;
unsigned int index = 0;
ch[0] = 0x0;
upcase_table = kcalloc(UTBL_COUNT, sizeof(unsigned short), GFP_KERNEL);
if (!upcase_table)
return -ENOMEM;
if (uni < 0x0080) {
ch[0] = (u8) uni;
return 1;
sbi->vol_utbl = upcase_table;
for (i = 0; index <= 0xFFFF && i < EXFAT_NUM_UPCASE; i++) {
uni = uni_def_upcase[i];
if (skip) {
index += uni;
skip = false;
} else if (uni == index) {
index++;
} else if (uni == 0xFFFF) {
skip = true;
} else {
upcase_table[index] = uni;
index++;
}
}
len = nls->uni2char(uni, ch, MAX_CHARSET_SIZE);
if (len < 0) {
/* conversion failed */
DMSG("%s: fail to use nls\n", __func__);
if (lossy != NULL)
*lossy |= NLS_NAME_LOSSY;
ch[0] = '_';
return 1;
}
return len;
if (index >= 0xFFFF)
return 0;
/* FATAL error: default upcase table has error */
exfat_free_upcase_table(sbi);
return ret;
}
int exfat_create_upcase_table(struct super_block *sb)
{
int i, ret;
unsigned int tbl_clu, type;
sector_t sector;
unsigned long long tbl_size, num_sectors;
unsigned char blksize_bits = sb->s_blocksize_bits;
struct exfat_chain clu;
struct exfat_dentry *ep;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct buffer_head *bh;
clu.dir = sbi->root_dir;
clu.flags = ALLOC_FAT_CHAIN;
while (clu.dir != EXFAT_EOF_CLUSTER) {
for (i = 0; i < sbi->dentries_per_clu; i++) {
ep = exfat_get_dentry(sb, &clu, i, &bh, NULL);
if (!ep)
return -EIO;
type = exfat_get_entry_type(ep);
if (type == TYPE_UNUSED) {
brelse(bh);
break;
}
if (type != TYPE_UPCASE) {
brelse(bh);
continue;
}
tbl_clu = le32_to_cpu(ep->dentry.upcase.start_clu);
tbl_size = le64_to_cpu(ep->dentry.upcase.size);
sector = exfat_cluster_to_sector(sbi, tbl_clu);
num_sectors = ((tbl_size - 1) >> blksize_bits) + 1;
ret = exfat_load_upcase_table(sb, sector, num_sectors,
le32_to_cpu(ep->dentry.upcase.checksum));
brelse(bh);
if (ret && ret != -EIO)
goto load_default;
/* load successfully */
return ret;
}
if (exfat_get_next_cluster(sb, &(clu.dir)))
return -EIO;
}
load_default:
/* load default upcase table */
return exfat_load_default_upcase_table(sb);
}
void exfat_free_upcase_table(struct exfat_sb_info *sbi)
{
kfree(sbi->vol_utbl);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,394 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*/
#ifndef _UPCASE_H
#define _UPCASE_H
/* Upcase tabel macro */
#define EXFAT_NUM_UPCASE 2918
#define HIGH_INDEX_BIT (8)
#define HIGH_INDEX_MASK (0xFF00)
#define LOW_INDEX_BIT (16-HIGH_INDEX_BIT)
#define UTBL_ROW_COUNT (1<<LOW_INDEX_BIT)
#define UTBL_COL_COUNT (1<<HIGH_INDEX_BIT)
static inline u16 exfat_get_col_index(u16 i)
{
return i >> LOW_INDEX_BIT;
}
static inline u16 exfat_get_row_index(u16 i)
{
return i & ~HIGH_INDEX_MASK;
}
static const u8 uni_def_upcase[EXFAT_NUM_UPCASE<<1] = {
0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00,
0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00,
0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x00,
0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00,
0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00, 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, 0x00,
0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00,
0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00, 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00,
0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00,
0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00,
0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, 0x00, 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00,
0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00,
0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00,
0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x7B, 0x00, 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00,
0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00,
0x88, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00,
0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00,
0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00, 0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00,
0xA0, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3, 0x00, 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, 0x00,
0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, 0x00, 0xAC, 0x00, 0xAD, 0x00, 0xAE, 0x00, 0xAF, 0x00,
0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, 0x00, 0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, 0x00,
0xB8, 0x00, 0xB9, 0x00, 0xBA, 0x00, 0xBB, 0x00, 0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0x00,
0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00,
0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00,
0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, 0x00,
0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0xDF, 0x00,
0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00,
0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00,
0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xF7, 0x00,
0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0x78, 0x01,
0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01,
0x08, 0x01, 0x08, 0x01, 0x0A, 0x01, 0x0A, 0x01, 0x0C, 0x01, 0x0C, 0x01, 0x0E, 0x01, 0x0E, 0x01,
0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01, 0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01,
0x18, 0x01, 0x18, 0x01, 0x1A, 0x01, 0x1A, 0x01, 0x1C, 0x01, 0x1C, 0x01, 0x1E, 0x01, 0x1E, 0x01,
0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01, 0x24, 0x01, 0x24, 0x01, 0x26, 0x01, 0x26, 0x01,
0x28, 0x01, 0x28, 0x01, 0x2A, 0x01, 0x2A, 0x01, 0x2C, 0x01, 0x2C, 0x01, 0x2E, 0x01, 0x2E, 0x01,
0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x32, 0x01, 0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01,
0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3B, 0x01, 0x3B, 0x01, 0x3D, 0x01, 0x3D, 0x01, 0x3F, 0x01,
0x3F, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01, 0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01,
0x47, 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4A, 0x01, 0x4C, 0x01, 0x4C, 0x01, 0x4E, 0x01, 0x4E, 0x01,
0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01, 0x54, 0x01, 0x54, 0x01, 0x56, 0x01, 0x56, 0x01,
0x58, 0x01, 0x58, 0x01, 0x5A, 0x01, 0x5A, 0x01, 0x5C, 0x01, 0x5C, 0x01, 0x5E, 0x01, 0x5E, 0x01,
0x60, 0x01, 0x60, 0x01, 0x62, 0x01, 0x62, 0x01, 0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01,
0x68, 0x01, 0x68, 0x01, 0x6A, 0x01, 0x6A, 0x01, 0x6C, 0x01, 0x6C, 0x01, 0x6E, 0x01, 0x6E, 0x01,
0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01, 0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01,
0x78, 0x01, 0x79, 0x01, 0x79, 0x01, 0x7B, 0x01, 0x7B, 0x01, 0x7D, 0x01, 0x7D, 0x01, 0x7F, 0x01,
0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01, 0x84, 0x01, 0x84, 0x01, 0x86, 0x01, 0x87, 0x01,
0x87, 0x01, 0x89, 0x01, 0x8A, 0x01, 0x8B, 0x01, 0x8B, 0x01, 0x8D, 0x01, 0x8E, 0x01, 0x8F, 0x01,
0x90, 0x01, 0x91, 0x01, 0x91, 0x01, 0x93, 0x01, 0x94, 0x01, 0xF6, 0x01, 0x96, 0x01, 0x97, 0x01,
0x98, 0x01, 0x98, 0x01, 0x3D, 0x02, 0x9B, 0x01, 0x9C, 0x01, 0x9D, 0x01, 0x20, 0x02, 0x9F, 0x01,
0xA0, 0x01, 0xA0, 0x01, 0xA2, 0x01, 0xA2, 0x01, 0xA4, 0x01, 0xA4, 0x01, 0xA6, 0x01, 0xA7, 0x01,
0xA7, 0x01, 0xA9, 0x01, 0xAA, 0x01, 0xAB, 0x01, 0xAC, 0x01, 0xAC, 0x01, 0xAE, 0x01, 0xAF, 0x01,
0xAF, 0x01, 0xB1, 0x01, 0xB2, 0x01, 0xB3, 0x01, 0xB3, 0x01, 0xB5, 0x01, 0xB5, 0x01, 0xB7, 0x01,
0xB8, 0x01, 0xB8, 0x01, 0xBA, 0x01, 0xBB, 0x01, 0xBC, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xF7, 0x01,
0xC0, 0x01, 0xC1, 0x01, 0xC2, 0x01, 0xC3, 0x01, 0xC4, 0x01, 0xC5, 0x01, 0xC4, 0x01, 0xC7, 0x01,
0xC8, 0x01, 0xC7, 0x01, 0xCA, 0x01, 0xCB, 0x01, 0xCA, 0x01, 0xCD, 0x01, 0xCD, 0x01, 0xCF, 0x01,
0xCF, 0x01, 0xD1, 0x01, 0xD1, 0x01, 0xD3, 0x01, 0xD3, 0x01, 0xD5, 0x01, 0xD5, 0x01, 0xD7, 0x01,
0xD7, 0x01, 0xD9, 0x01, 0xD9, 0x01, 0xDB, 0x01, 0xDB, 0x01, 0x8E, 0x01, 0xDE, 0x01, 0xDE, 0x01,
0xE0, 0x01, 0xE0, 0x01, 0xE2, 0x01, 0xE2, 0x01, 0xE4, 0x01, 0xE4, 0x01, 0xE6, 0x01, 0xE6, 0x01,
0xE8, 0x01, 0xE8, 0x01, 0xEA, 0x01, 0xEA, 0x01, 0xEC, 0x01, 0xEC, 0x01, 0xEE, 0x01, 0xEE, 0x01,
0xF0, 0x01, 0xF1, 0x01, 0xF2, 0x01, 0xF1, 0x01, 0xF4, 0x01, 0xF4, 0x01, 0xF6, 0x01, 0xF7, 0x01,
0xF8, 0x01, 0xF8, 0x01, 0xFA, 0x01, 0xFA, 0x01, 0xFC, 0x01, 0xFC, 0x01, 0xFE, 0x01, 0xFE, 0x01,
0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02,
0x08, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x0A, 0x02, 0x0C, 0x02, 0x0C, 0x02, 0x0E, 0x02, 0x0E, 0x02,
0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02, 0x14, 0x02, 0x14, 0x02, 0x16, 0x02, 0x16, 0x02,
0x18, 0x02, 0x18, 0x02, 0x1A, 0x02, 0x1A, 0x02, 0x1C, 0x02, 0x1C, 0x02, 0x1E, 0x02, 0x1E, 0x02,
0x20, 0x02, 0x21, 0x02, 0x22, 0x02, 0x22, 0x02, 0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02,
0x28, 0x02, 0x28, 0x02, 0x2A, 0x02, 0x2A, 0x02, 0x2C, 0x02, 0x2C, 0x02, 0x2E, 0x02, 0x2E, 0x02,
0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02, 0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02,
0x38, 0x02, 0x39, 0x02, 0x65, 0x2C, 0x3B, 0x02, 0x3B, 0x02, 0x3D, 0x02, 0x66, 0x2C, 0x3F, 0x02,
0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02, 0x44, 0x02, 0x45, 0x02, 0x46, 0x02, 0x46, 0x02,
0x48, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x4A, 0x02, 0x4C, 0x02, 0x4C, 0x02, 0x4E, 0x02, 0x4E, 0x02,
0x50, 0x02, 0x51, 0x02, 0x52, 0x02, 0x81, 0x01, 0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8A, 0x01,
0x58, 0x02, 0x8F, 0x01, 0x5A, 0x02, 0x90, 0x01, 0x5C, 0x02, 0x5D, 0x02, 0x5E, 0x02, 0x5F, 0x02,
0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01, 0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02,
0x97, 0x01, 0x96, 0x01, 0x6A, 0x02, 0x62, 0x2C, 0x6C, 0x02, 0x6D, 0x02, 0x6E, 0x02, 0x9C, 0x01,
0x70, 0x02, 0x71, 0x02, 0x9D, 0x01, 0x73, 0x02, 0x74, 0x02, 0x9F, 0x01, 0x76, 0x02, 0x77, 0x02,
0x78, 0x02, 0x79, 0x02, 0x7A, 0x02, 0x7B, 0x02, 0x7C, 0x02, 0x64, 0x2C, 0x7E, 0x02, 0x7F, 0x02,
0xA6, 0x01, 0x81, 0x02, 0x82, 0x02, 0xA9, 0x01, 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02,
0xAE, 0x01, 0x44, 0x02, 0xB1, 0x01, 0xB2, 0x01, 0x45, 0x02, 0x8D, 0x02, 0x8E, 0x02, 0x8F, 0x02,
0x90, 0x02, 0x91, 0x02, 0xB7, 0x01, 0x93, 0x02, 0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02,
0x98, 0x02, 0x99, 0x02, 0x9A, 0x02, 0x9B, 0x02, 0x9C, 0x02, 0x9D, 0x02, 0x9E, 0x02, 0x9F, 0x02,
0xA0, 0x02, 0xA1, 0x02, 0xA2, 0x02, 0xA3, 0x02, 0xA4, 0x02, 0xA5, 0x02, 0xA6, 0x02, 0xA7, 0x02,
0xA8, 0x02, 0xA9, 0x02, 0xAA, 0x02, 0xAB, 0x02, 0xAC, 0x02, 0xAD, 0x02, 0xAE, 0x02, 0xAF, 0x02,
0xB0, 0x02, 0xB1, 0x02, 0xB2, 0x02, 0xB3, 0x02, 0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, 0xB7, 0x02,
0xB8, 0x02, 0xB9, 0x02, 0xBA, 0x02, 0xBB, 0x02, 0xBC, 0x02, 0xBD, 0x02, 0xBE, 0x02, 0xBF, 0x02,
0xC0, 0x02, 0xC1, 0x02, 0xC2, 0x02, 0xC3, 0x02, 0xC4, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC7, 0x02,
0xC8, 0x02, 0xC9, 0x02, 0xCA, 0x02, 0xCB, 0x02, 0xCC, 0x02, 0xCD, 0x02, 0xCE, 0x02, 0xCF, 0x02,
0xD0, 0x02, 0xD1, 0x02, 0xD2, 0x02, 0xD3, 0x02, 0xD4, 0x02, 0xD5, 0x02, 0xD6, 0x02, 0xD7, 0x02,
0xD8, 0x02, 0xD9, 0x02, 0xDA, 0x02, 0xDB, 0x02, 0xDC, 0x02, 0xDD, 0x02, 0xDE, 0x02, 0xDF, 0x02,
0xE0, 0x02, 0xE1, 0x02, 0xE2, 0x02, 0xE3, 0x02, 0xE4, 0x02, 0xE5, 0x02, 0xE6, 0x02, 0xE7, 0x02,
0xE8, 0x02, 0xE9, 0x02, 0xEA, 0x02, 0xEB, 0x02, 0xEC, 0x02, 0xED, 0x02, 0xEE, 0x02, 0xEF, 0x02,
0xF0, 0x02, 0xF1, 0x02, 0xF2, 0x02, 0xF3, 0x02, 0xF4, 0x02, 0xF5, 0x02, 0xF6, 0x02, 0xF7, 0x02,
0xF8, 0x02, 0xF9, 0x02, 0xFA, 0x02, 0xFB, 0x02, 0xFC, 0x02, 0xFD, 0x02, 0xFE, 0x02, 0xFF, 0x02,
0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, 0x03,
0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, 0x03, 0x0C, 0x03, 0x0D, 0x03, 0x0E, 0x03, 0x0F, 0x03,
0x10, 0x03, 0x11, 0x03, 0x12, 0x03, 0x13, 0x03, 0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03,
0x18, 0x03, 0x19, 0x03, 0x1A, 0x03, 0x1B, 0x03, 0x1C, 0x03, 0x1D, 0x03, 0x1E, 0x03, 0x1F, 0x03,
0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03, 0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03,
0x28, 0x03, 0x29, 0x03, 0x2A, 0x03, 0x2B, 0x03, 0x2C, 0x03, 0x2D, 0x03, 0x2E, 0x03, 0x2F, 0x03,
0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03, 0x34, 0x03, 0x35, 0x03, 0x36, 0x03, 0x37, 0x03,
0x38, 0x03, 0x39, 0x03, 0x3A, 0x03, 0x3B, 0x03, 0x3C, 0x03, 0x3D, 0x03, 0x3E, 0x03, 0x3F, 0x03,
0x40, 0x03, 0x41, 0x03, 0x42, 0x03, 0x43, 0x03, 0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03,
0x48, 0x03, 0x49, 0x03, 0x4A, 0x03, 0x4B, 0x03, 0x4C, 0x03, 0x4D, 0x03, 0x4E, 0x03, 0x4F, 0x03,
0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03, 0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03,
0x58, 0x03, 0x59, 0x03, 0x5A, 0x03, 0x5B, 0x03, 0x5C, 0x03, 0x5D, 0x03, 0x5E, 0x03, 0x5F, 0x03,
0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03, 0x64, 0x03, 0x65, 0x03, 0x66, 0x03, 0x67, 0x03,
0x68, 0x03, 0x69, 0x03, 0x6A, 0x03, 0x6B, 0x03, 0x6C, 0x03, 0x6D, 0x03, 0x6E, 0x03, 0x6F, 0x03,
0x70, 0x03, 0x71, 0x03, 0x72, 0x03, 0x73, 0x03, 0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03,
0x78, 0x03, 0x79, 0x03, 0x7A, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03, 0x7E, 0x03, 0x7F, 0x03,
0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03, 0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03,
0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, 0x8B, 0x03, 0x8C, 0x03, 0x8D, 0x03, 0x8E, 0x03, 0x8F, 0x03,
0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03,
0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03,
0xA0, 0x03, 0xA1, 0x03, 0xA2, 0x03, 0xA3, 0x03, 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03,
0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, 0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03,
0xB0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03,
0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03,
0xA0, 0x03, 0xA1, 0x03, 0xA3, 0x03, 0xA3, 0x03, 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03,
0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, 0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0xCF, 0x03,
0xD0, 0x03, 0xD1, 0x03, 0xD2, 0x03, 0xD3, 0x03, 0xD4, 0x03, 0xD5, 0x03, 0xD6, 0x03, 0xD7, 0x03,
0xD8, 0x03, 0xD8, 0x03, 0xDA, 0x03, 0xDA, 0x03, 0xDC, 0x03, 0xDC, 0x03, 0xDE, 0x03, 0xDE, 0x03,
0xE0, 0x03, 0xE0, 0x03, 0xE2, 0x03, 0xE2, 0x03, 0xE4, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE6, 0x03,
0xE8, 0x03, 0xE8, 0x03, 0xEA, 0x03, 0xEA, 0x03, 0xEC, 0x03, 0xEC, 0x03, 0xEE, 0x03, 0xEE, 0x03,
0xF0, 0x03, 0xF1, 0x03, 0xF9, 0x03, 0xF3, 0x03, 0xF4, 0x03, 0xF5, 0x03, 0xF6, 0x03, 0xF7, 0x03,
0xF7, 0x03, 0xF9, 0x03, 0xFA, 0x03, 0xFA, 0x03, 0xFC, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03,
0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04,
0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04,
0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04,
0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04,
0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04,
0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04,
0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04,
0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04,
0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04,
0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04,
0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04,
0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04,
0x60, 0x04, 0x60, 0x04, 0x62, 0x04, 0x62, 0x04, 0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04,
0x68, 0x04, 0x68, 0x04, 0x6A, 0x04, 0x6A, 0x04, 0x6C, 0x04, 0x6C, 0x04, 0x6E, 0x04, 0x6E, 0x04,
0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04, 0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04,
0x78, 0x04, 0x78, 0x04, 0x7A, 0x04, 0x7A, 0x04, 0x7C, 0x04, 0x7C, 0x04, 0x7E, 0x04, 0x7E, 0x04,
0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04, 0x84, 0x04, 0x85, 0x04, 0x86, 0x04, 0x87, 0x04,
0x88, 0x04, 0x89, 0x04, 0x8A, 0x04, 0x8A, 0x04, 0x8C, 0x04, 0x8C, 0x04, 0x8E, 0x04, 0x8E, 0x04,
0x90, 0x04, 0x90, 0x04, 0x92, 0x04, 0x92, 0x04, 0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04,
0x98, 0x04, 0x98, 0x04, 0x9A, 0x04, 0x9A, 0x04, 0x9C, 0x04, 0x9C, 0x04, 0x9E, 0x04, 0x9E, 0x04,
0xA0, 0x04, 0xA0, 0x04, 0xA2, 0x04, 0xA2, 0x04, 0xA4, 0x04, 0xA4, 0x04, 0xA6, 0x04, 0xA6, 0x04,
0xA8, 0x04, 0xA8, 0x04, 0xAA, 0x04, 0xAA, 0x04, 0xAC, 0x04, 0xAC, 0x04, 0xAE, 0x04, 0xAE, 0x04,
0xB0, 0x04, 0xB0, 0x04, 0xB2, 0x04, 0xB2, 0x04, 0xB4, 0x04, 0xB4, 0x04, 0xB6, 0x04, 0xB6, 0x04,
0xB8, 0x04, 0xB8, 0x04, 0xBA, 0x04, 0xBA, 0x04, 0xBC, 0x04, 0xBC, 0x04, 0xBE, 0x04, 0xBE, 0x04,
0xC0, 0x04, 0xC1, 0x04, 0xC1, 0x04, 0xC3, 0x04, 0xC3, 0x04, 0xC5, 0x04, 0xC5, 0x04, 0xC7, 0x04,
0xC7, 0x04, 0xC9, 0x04, 0xC9, 0x04, 0xCB, 0x04, 0xCB, 0x04, 0xCD, 0x04, 0xCD, 0x04, 0xC0, 0x04,
0xD0, 0x04, 0xD0, 0x04, 0xD2, 0x04, 0xD2, 0x04, 0xD4, 0x04, 0xD4, 0x04, 0xD6, 0x04, 0xD6, 0x04,
0xD8, 0x04, 0xD8, 0x04, 0xDA, 0x04, 0xDA, 0x04, 0xDC, 0x04, 0xDC, 0x04, 0xDE, 0x04, 0xDE, 0x04,
0xE0, 0x04, 0xE0, 0x04, 0xE2, 0x04, 0xE2, 0x04, 0xE4, 0x04, 0xE4, 0x04, 0xE6, 0x04, 0xE6, 0x04,
0xE8, 0x04, 0xE8, 0x04, 0xEA, 0x04, 0xEA, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEE, 0x04, 0xEE, 0x04,
0xF0, 0x04, 0xF0, 0x04, 0xF2, 0x04, 0xF2, 0x04, 0xF4, 0x04, 0xF4, 0x04, 0xF6, 0x04, 0xF6, 0x04,
0xF8, 0x04, 0xF8, 0x04, 0xFA, 0x04, 0xFA, 0x04, 0xFC, 0x04, 0xFC, 0x04, 0xFE, 0x04, 0xFE, 0x04,
0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05, 0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05,
0x08, 0x05, 0x08, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0C, 0x05, 0x0C, 0x05, 0x0E, 0x05, 0x0E, 0x05,
0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05, 0x14, 0x05, 0x15, 0x05, 0x16, 0x05, 0x17, 0x05,
0x18, 0x05, 0x19, 0x05, 0x1A, 0x05, 0x1B, 0x05, 0x1C, 0x05, 0x1D, 0x05, 0x1E, 0x05, 0x1F, 0x05,
0x20, 0x05, 0x21, 0x05, 0x22, 0x05, 0x23, 0x05, 0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05,
0x28, 0x05, 0x29, 0x05, 0x2A, 0x05, 0x2B, 0x05, 0x2C, 0x05, 0x2D, 0x05, 0x2E, 0x05, 0x2F, 0x05,
0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05,
0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05,
0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05,
0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05,
0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05,
0x58, 0x05, 0x59, 0x05, 0x5A, 0x05, 0x5B, 0x05, 0x5C, 0x05, 0x5D, 0x05, 0x5E, 0x05, 0x5F, 0x05,
0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05,
0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05,
0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05,
0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05,
0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xFF, 0xFF,
0xF6, 0x17, 0x63, 0x2C, 0x7E, 0x1D, 0x7F, 0x1D, 0x80, 0x1D, 0x81, 0x1D, 0x82, 0x1D, 0x83, 0x1D,
0x84, 0x1D, 0x85, 0x1D, 0x86, 0x1D, 0x87, 0x1D, 0x88, 0x1D, 0x89, 0x1D, 0x8A, 0x1D, 0x8B, 0x1D,
0x8C, 0x1D, 0x8D, 0x1D, 0x8E, 0x1D, 0x8F, 0x1D, 0x90, 0x1D, 0x91, 0x1D, 0x92, 0x1D, 0x93, 0x1D,
0x94, 0x1D, 0x95, 0x1D, 0x96, 0x1D, 0x97, 0x1D, 0x98, 0x1D, 0x99, 0x1D, 0x9A, 0x1D, 0x9B, 0x1D,
0x9C, 0x1D, 0x9D, 0x1D, 0x9E, 0x1D, 0x9F, 0x1D, 0xA0, 0x1D, 0xA1, 0x1D, 0xA2, 0x1D, 0xA3, 0x1D,
0xA4, 0x1D, 0xA5, 0x1D, 0xA6, 0x1D, 0xA7, 0x1D, 0xA8, 0x1D, 0xA9, 0x1D, 0xAA, 0x1D, 0xAB, 0x1D,
0xAC, 0x1D, 0xAD, 0x1D, 0xAE, 0x1D, 0xAF, 0x1D, 0xB0, 0x1D, 0xB1, 0x1D, 0xB2, 0x1D, 0xB3, 0x1D,
0xB4, 0x1D, 0xB5, 0x1D, 0xB6, 0x1D, 0xB7, 0x1D, 0xB8, 0x1D, 0xB9, 0x1D, 0xBA, 0x1D, 0xBB, 0x1D,
0xBC, 0x1D, 0xBD, 0x1D, 0xBE, 0x1D, 0xBF, 0x1D, 0xC0, 0x1D, 0xC1, 0x1D, 0xC2, 0x1D, 0xC3, 0x1D,
0xC4, 0x1D, 0xC5, 0x1D, 0xC6, 0x1D, 0xC7, 0x1D, 0xC8, 0x1D, 0xC9, 0x1D, 0xCA, 0x1D, 0xCB, 0x1D,
0xCC, 0x1D, 0xCD, 0x1D, 0xCE, 0x1D, 0xCF, 0x1D, 0xD0, 0x1D, 0xD1, 0x1D, 0xD2, 0x1D, 0xD3, 0x1D,
0xD4, 0x1D, 0xD5, 0x1D, 0xD6, 0x1D, 0xD7, 0x1D, 0xD8, 0x1D, 0xD9, 0x1D, 0xDA, 0x1D, 0xDB, 0x1D,
0xDC, 0x1D, 0xDD, 0x1D, 0xDE, 0x1D, 0xDF, 0x1D, 0xE0, 0x1D, 0xE1, 0x1D, 0xE2, 0x1D, 0xE3, 0x1D,
0xE4, 0x1D, 0xE5, 0x1D, 0xE6, 0x1D, 0xE7, 0x1D, 0xE8, 0x1D, 0xE9, 0x1D, 0xEA, 0x1D, 0xEB, 0x1D,
0xEC, 0x1D, 0xED, 0x1D, 0xEE, 0x1D, 0xEF, 0x1D, 0xF0, 0x1D, 0xF1, 0x1D, 0xF2, 0x1D, 0xF3, 0x1D,
0xF4, 0x1D, 0xF5, 0x1D, 0xF6, 0x1D, 0xF7, 0x1D, 0xF8, 0x1D, 0xF9, 0x1D, 0xFA, 0x1D, 0xFB, 0x1D,
0xFC, 0x1D, 0xFD, 0x1D, 0xFE, 0x1D, 0xFF, 0x1D, 0x00, 0x1E, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E,
0x04, 0x1E, 0x04, 0x1E, 0x06, 0x1E, 0x06, 0x1E, 0x08, 0x1E, 0x08, 0x1E, 0x0A, 0x1E, 0x0A, 0x1E,
0x0C, 0x1E, 0x0C, 0x1E, 0x0E, 0x1E, 0x0E, 0x1E, 0x10, 0x1E, 0x10, 0x1E, 0x12, 0x1E, 0x12, 0x1E,
0x14, 0x1E, 0x14, 0x1E, 0x16, 0x1E, 0x16, 0x1E, 0x18, 0x1E, 0x18, 0x1E, 0x1A, 0x1E, 0x1A, 0x1E,
0x1C, 0x1E, 0x1C, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x20, 0x1E, 0x20, 0x1E, 0x22, 0x1E, 0x22, 0x1E,
0x24, 0x1E, 0x24, 0x1E, 0x26, 0x1E, 0x26, 0x1E, 0x28, 0x1E, 0x28, 0x1E, 0x2A, 0x1E, 0x2A, 0x1E,
0x2C, 0x1E, 0x2C, 0x1E, 0x2E, 0x1E, 0x2E, 0x1E, 0x30, 0x1E, 0x30, 0x1E, 0x32, 0x1E, 0x32, 0x1E,
0x34, 0x1E, 0x34, 0x1E, 0x36, 0x1E, 0x36, 0x1E, 0x38, 0x1E, 0x38, 0x1E, 0x3A, 0x1E, 0x3A, 0x1E,
0x3C, 0x1E, 0x3C, 0x1E, 0x3E, 0x1E, 0x3E, 0x1E, 0x40, 0x1E, 0x40, 0x1E, 0x42, 0x1E, 0x42, 0x1E,
0x44, 0x1E, 0x44, 0x1E, 0x46, 0x1E, 0x46, 0x1E, 0x48, 0x1E, 0x48, 0x1E, 0x4A, 0x1E, 0x4A, 0x1E,
0x4C, 0x1E, 0x4C, 0x1E, 0x4E, 0x1E, 0x4E, 0x1E, 0x50, 0x1E, 0x50, 0x1E, 0x52, 0x1E, 0x52, 0x1E,
0x54, 0x1E, 0x54, 0x1E, 0x56, 0x1E, 0x56, 0x1E, 0x58, 0x1E, 0x58, 0x1E, 0x5A, 0x1E, 0x5A, 0x1E,
0x5C, 0x1E, 0x5C, 0x1E, 0x5E, 0x1E, 0x5E, 0x1E, 0x60, 0x1E, 0x60, 0x1E, 0x62, 0x1E, 0x62, 0x1E,
0x64, 0x1E, 0x64, 0x1E, 0x66, 0x1E, 0x66, 0x1E, 0x68, 0x1E, 0x68, 0x1E, 0x6A, 0x1E, 0x6A, 0x1E,
0x6C, 0x1E, 0x6C, 0x1E, 0x6E, 0x1E, 0x6E, 0x1E, 0x70, 0x1E, 0x70, 0x1E, 0x72, 0x1E, 0x72, 0x1E,
0x74, 0x1E, 0x74, 0x1E, 0x76, 0x1E, 0x76, 0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x7A, 0x1E, 0x7A, 0x1E,
0x7C, 0x1E, 0x7C, 0x1E, 0x7E, 0x1E, 0x7E, 0x1E, 0x80, 0x1E, 0x80, 0x1E, 0x82, 0x1E, 0x82, 0x1E,
0x84, 0x1E, 0x84, 0x1E, 0x86, 0x1E, 0x86, 0x1E, 0x88, 0x1E, 0x88, 0x1E, 0x8A, 0x1E, 0x8A, 0x1E,
0x8C, 0x1E, 0x8C, 0x1E, 0x8E, 0x1E, 0x8E, 0x1E, 0x90, 0x1E, 0x90, 0x1E, 0x92, 0x1E, 0x92, 0x1E,
0x94, 0x1E, 0x94, 0x1E, 0x96, 0x1E, 0x97, 0x1E, 0x98, 0x1E, 0x99, 0x1E, 0x9A, 0x1E, 0x9B, 0x1E,
0x9C, 0x1E, 0x9D, 0x1E, 0x9E, 0x1E, 0x9F, 0x1E, 0xA0, 0x1E, 0xA0, 0x1E, 0xA2, 0x1E, 0xA2, 0x1E,
0xA4, 0x1E, 0xA4, 0x1E, 0xA6, 0x1E, 0xA6, 0x1E, 0xA8, 0x1E, 0xA8, 0x1E, 0xAA, 0x1E, 0xAA, 0x1E,
0xAC, 0x1E, 0xAC, 0x1E, 0xAE, 0x1E, 0xAE, 0x1E, 0xB0, 0x1E, 0xB0, 0x1E, 0xB2, 0x1E, 0xB2, 0x1E,
0xB4, 0x1E, 0xB4, 0x1E, 0xB6, 0x1E, 0xB6, 0x1E, 0xB8, 0x1E, 0xB8, 0x1E, 0xBA, 0x1E, 0xBA, 0x1E,
0xBC, 0x1E, 0xBC, 0x1E, 0xBE, 0x1E, 0xBE, 0x1E, 0xC0, 0x1E, 0xC0, 0x1E, 0xC2, 0x1E, 0xC2, 0x1E,
0xC4, 0x1E, 0xC4, 0x1E, 0xC6, 0x1E, 0xC6, 0x1E, 0xC8, 0x1E, 0xC8, 0x1E, 0xCA, 0x1E, 0xCA, 0x1E,
0xCC, 0x1E, 0xCC, 0x1E, 0xCE, 0x1E, 0xCE, 0x1E, 0xD0, 0x1E, 0xD0, 0x1E, 0xD2, 0x1E, 0xD2, 0x1E,
0xD4, 0x1E, 0xD4, 0x1E, 0xD6, 0x1E, 0xD6, 0x1E, 0xD8, 0x1E, 0xD8, 0x1E, 0xDA, 0x1E, 0xDA, 0x1E,
0xDC, 0x1E, 0xDC, 0x1E, 0xDE, 0x1E, 0xDE, 0x1E, 0xE0, 0x1E, 0xE0, 0x1E, 0xE2, 0x1E, 0xE2, 0x1E,
0xE4, 0x1E, 0xE4, 0x1E, 0xE6, 0x1E, 0xE6, 0x1E, 0xE8, 0x1E, 0xE8, 0x1E, 0xEA, 0x1E, 0xEA, 0x1E,
0xEC, 0x1E, 0xEC, 0x1E, 0xEE, 0x1E, 0xEE, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF2, 0x1E, 0xF2, 0x1E,
0xF4, 0x1E, 0xF4, 0x1E, 0xF6, 0x1E, 0xF6, 0x1E, 0xF8, 0x1E, 0xF8, 0x1E, 0xFA, 0x1E, 0xFB, 0x1E,
0xFC, 0x1E, 0xFD, 0x1E, 0xFE, 0x1E, 0xFF, 0x1E, 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F,
0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F,
0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F,
0x1C, 0x1F, 0x1D, 0x1F, 0x16, 0x1F, 0x17, 0x1F, 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F,
0x1C, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1F, 0x1F, 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F,
0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F,
0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F,
0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F,
0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F,
0x4C, 0x1F, 0x4D, 0x1F, 0x46, 0x1F, 0x47, 0x1F, 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F,
0x4C, 0x1F, 0x4D, 0x1F, 0x4E, 0x1F, 0x4F, 0x1F, 0x50, 0x1F, 0x59, 0x1F, 0x52, 0x1F, 0x5B, 0x1F,
0x54, 0x1F, 0x5D, 0x1F, 0x56, 0x1F, 0x5F, 0x1F, 0x58, 0x1F, 0x59, 0x1F, 0x5A, 0x1F, 0x5B, 0x1F,
0x5C, 0x1F, 0x5D, 0x1F, 0x5E, 0x1F, 0x5F, 0x1F, 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F,
0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F,
0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F,
0xCA, 0x1F, 0xCB, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, 0xF8, 0x1F, 0xF9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F,
0xFA, 0x1F, 0xFB, 0x1F, 0x7E, 0x1F, 0x7F, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F,
0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F,
0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F,
0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F,
0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F,
0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F,
0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xB8, 0x1F, 0xB9, 0x1F, 0xB2, 0x1F, 0xBC, 0x1F,
0xB4, 0x1F, 0xB5, 0x1F, 0xB6, 0x1F, 0xB7, 0x1F, 0xB8, 0x1F, 0xB9, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F,
0xBC, 0x1F, 0xBD, 0x1F, 0xBE, 0x1F, 0xBF, 0x1F, 0xC0, 0x1F, 0xC1, 0x1F, 0xC2, 0x1F, 0xC3, 0x1F,
0xC4, 0x1F, 0xC5, 0x1F, 0xC6, 0x1F, 0xC7, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F, 0xCA, 0x1F, 0xCB, 0x1F,
0xC3, 0x1F, 0xCD, 0x1F, 0xCE, 0x1F, 0xCF, 0x1F, 0xD8, 0x1F, 0xD9, 0x1F, 0xD2, 0x1F, 0xD3, 0x1F,
0xD4, 0x1F, 0xD5, 0x1F, 0xD6, 0x1F, 0xD7, 0x1F, 0xD8, 0x1F, 0xD9, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F,
0xDC, 0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xDF, 0x1F, 0xE8, 0x1F, 0xE9, 0x1F, 0xE2, 0x1F, 0xE3, 0x1F,
0xE4, 0x1F, 0xEC, 0x1F, 0xE6, 0x1F, 0xE7, 0x1F, 0xE8, 0x1F, 0xE9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F,
0xEC, 0x1F, 0xED, 0x1F, 0xEE, 0x1F, 0xEF, 0x1F, 0xF0, 0x1F, 0xF1, 0x1F, 0xF2, 0x1F, 0xF3, 0x1F,
0xF4, 0x1F, 0xF5, 0x1F, 0xF6, 0x1F, 0xF7, 0x1F, 0xF8, 0x1F, 0xF9, 0x1F, 0xFA, 0x1F, 0xFB, 0x1F,
0xF3, 0x1F, 0xFD, 0x1F, 0xFE, 0x1F, 0xFF, 0x1F, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20,
0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x09, 0x20, 0x0A, 0x20, 0x0B, 0x20,
0x0C, 0x20, 0x0D, 0x20, 0x0E, 0x20, 0x0F, 0x20, 0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20,
0x14, 0x20, 0x15, 0x20, 0x16, 0x20, 0x17, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1A, 0x20, 0x1B, 0x20,
0x1C, 0x20, 0x1D, 0x20, 0x1E, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, 0x22, 0x20, 0x23, 0x20,
0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20, 0x28, 0x20, 0x29, 0x20, 0x2A, 0x20, 0x2B, 0x20,
0x2C, 0x20, 0x2D, 0x20, 0x2E, 0x20, 0x2F, 0x20, 0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20,
0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20, 0x38, 0x20, 0x39, 0x20, 0x3A, 0x20, 0x3B, 0x20,
0x3C, 0x20, 0x3D, 0x20, 0x3E, 0x20, 0x3F, 0x20, 0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20,
0x44, 0x20, 0x45, 0x20, 0x46, 0x20, 0x47, 0x20, 0x48, 0x20, 0x49, 0x20, 0x4A, 0x20, 0x4B, 0x20,
0x4C, 0x20, 0x4D, 0x20, 0x4E, 0x20, 0x4F, 0x20, 0x50, 0x20, 0x51, 0x20, 0x52, 0x20, 0x53, 0x20,
0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20, 0x58, 0x20, 0x59, 0x20, 0x5A, 0x20, 0x5B, 0x20,
0x5C, 0x20, 0x5D, 0x20, 0x5E, 0x20, 0x5F, 0x20, 0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20,
0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20, 0x68, 0x20, 0x69, 0x20, 0x6A, 0x20, 0x6B, 0x20,
0x6C, 0x20, 0x6D, 0x20, 0x6E, 0x20, 0x6F, 0x20, 0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20,
0x74, 0x20, 0x75, 0x20, 0x76, 0x20, 0x77, 0x20, 0x78, 0x20, 0x79, 0x20, 0x7A, 0x20, 0x7B, 0x20,
0x7C, 0x20, 0x7D, 0x20, 0x7E, 0x20, 0x7F, 0x20, 0x80, 0x20, 0x81, 0x20, 0x82, 0x20, 0x83, 0x20,
0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x8A, 0x20, 0x8B, 0x20,
0x8C, 0x20, 0x8D, 0x20, 0x8E, 0x20, 0x8F, 0x20, 0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20,
0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20, 0x98, 0x20, 0x99, 0x20, 0x9A, 0x20, 0x9B, 0x20,
0x9C, 0x20, 0x9D, 0x20, 0x9E, 0x20, 0x9F, 0x20, 0xA0, 0x20, 0xA1, 0x20, 0xA2, 0x20, 0xA3, 0x20,
0xA4, 0x20, 0xA5, 0x20, 0xA6, 0x20, 0xA7, 0x20, 0xA8, 0x20, 0xA9, 0x20, 0xAA, 0x20, 0xAB, 0x20,
0xAC, 0x20, 0xAD, 0x20, 0xAE, 0x20, 0xAF, 0x20, 0xB0, 0x20, 0xB1, 0x20, 0xB2, 0x20, 0xB3, 0x20,
0xB4, 0x20, 0xB5, 0x20, 0xB6, 0x20, 0xB7, 0x20, 0xB8, 0x20, 0xB9, 0x20, 0xBA, 0x20, 0xBB, 0x20,
0xBC, 0x20, 0xBD, 0x20, 0xBE, 0x20, 0xBF, 0x20, 0xC0, 0x20, 0xC1, 0x20, 0xC2, 0x20, 0xC3, 0x20,
0xC4, 0x20, 0xC5, 0x20, 0xC6, 0x20, 0xC7, 0x20, 0xC8, 0x20, 0xC9, 0x20, 0xCA, 0x20, 0xCB, 0x20,
0xCC, 0x20, 0xCD, 0x20, 0xCE, 0x20, 0xCF, 0x20, 0xD0, 0x20, 0xD1, 0x20, 0xD2, 0x20, 0xD3, 0x20,
0xD4, 0x20, 0xD5, 0x20, 0xD6, 0x20, 0xD7, 0x20, 0xD8, 0x20, 0xD9, 0x20, 0xDA, 0x20, 0xDB, 0x20,
0xDC, 0x20, 0xDD, 0x20, 0xDE, 0x20, 0xDF, 0x20, 0xE0, 0x20, 0xE1, 0x20, 0xE2, 0x20, 0xE3, 0x20,
0xE4, 0x20, 0xE5, 0x20, 0xE6, 0x20, 0xE7, 0x20, 0xE8, 0x20, 0xE9, 0x20, 0xEA, 0x20, 0xEB, 0x20,
0xEC, 0x20, 0xED, 0x20, 0xEE, 0x20, 0xEF, 0x20, 0xF0, 0x20, 0xF1, 0x20, 0xF2, 0x20, 0xF3, 0x20,
0xF4, 0x20, 0xF5, 0x20, 0xF6, 0x20, 0xF7, 0x20, 0xF8, 0x20, 0xF9, 0x20, 0xFA, 0x20, 0xFB, 0x20,
0xFC, 0x20, 0xFD, 0x20, 0xFE, 0x20, 0xFF, 0x20, 0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21,
0x04, 0x21, 0x05, 0x21, 0x06, 0x21, 0x07, 0x21, 0x08, 0x21, 0x09, 0x21, 0x0A, 0x21, 0x0B, 0x21,
0x0C, 0x21, 0x0D, 0x21, 0x0E, 0x21, 0x0F, 0x21, 0x10, 0x21, 0x11, 0x21, 0x12, 0x21, 0x13, 0x21,
0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21, 0x18, 0x21, 0x19, 0x21, 0x1A, 0x21, 0x1B, 0x21,
0x1C, 0x21, 0x1D, 0x21, 0x1E, 0x21, 0x1F, 0x21, 0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21,
0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21, 0x28, 0x21, 0x29, 0x21, 0x2A, 0x21, 0x2B, 0x21,
0x2C, 0x21, 0x2D, 0x21, 0x2E, 0x21, 0x2F, 0x21, 0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21,
0x34, 0x21, 0x35, 0x21, 0x36, 0x21, 0x37, 0x21, 0x38, 0x21, 0x39, 0x21, 0x3A, 0x21, 0x3B, 0x21,
0x3C, 0x21, 0x3D, 0x21, 0x3E, 0x21, 0x3F, 0x21, 0x40, 0x21, 0x41, 0x21, 0x42, 0x21, 0x43, 0x21,
0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21, 0x48, 0x21, 0x49, 0x21, 0x4A, 0x21, 0x4B, 0x21,
0x4C, 0x21, 0x4D, 0x21, 0x32, 0x21, 0x4F, 0x21, 0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21,
0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21, 0x58, 0x21, 0x59, 0x21, 0x5A, 0x21, 0x5B, 0x21,
0x5C, 0x21, 0x5D, 0x21, 0x5E, 0x21, 0x5F, 0x21, 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21,
0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21,
0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21,
0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21,
0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, 0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21,
0x83, 0x21, 0xFF, 0xFF, 0x4B, 0x03, 0xB6, 0x24, 0xB7, 0x24, 0xB8, 0x24, 0xB9, 0x24, 0xBA, 0x24,
0xBB, 0x24, 0xBC, 0x24, 0xBD, 0x24, 0xBE, 0x24, 0xBF, 0x24, 0xC0, 0x24, 0xC1, 0x24, 0xC2, 0x24,
0xC3, 0x24, 0xC4, 0x24, 0xC5, 0x24, 0xC6, 0x24, 0xC7, 0x24, 0xC8, 0x24, 0xC9, 0x24, 0xCA, 0x24,
0xCB, 0x24, 0xCC, 0x24, 0xCD, 0x24, 0xCE, 0x24, 0xCF, 0x24, 0xFF, 0xFF, 0x46, 0x07, 0x00, 0x2C,
0x01, 0x2C, 0x02, 0x2C, 0x03, 0x2C, 0x04, 0x2C, 0x05, 0x2C, 0x06, 0x2C, 0x07, 0x2C, 0x08, 0x2C,
0x09, 0x2C, 0x0A, 0x2C, 0x0B, 0x2C, 0x0C, 0x2C, 0x0D, 0x2C, 0x0E, 0x2C, 0x0F, 0x2C, 0x10, 0x2C,
0x11, 0x2C, 0x12, 0x2C, 0x13, 0x2C, 0x14, 0x2C, 0x15, 0x2C, 0x16, 0x2C, 0x17, 0x2C, 0x18, 0x2C,
0x19, 0x2C, 0x1A, 0x2C, 0x1B, 0x2C, 0x1C, 0x2C, 0x1D, 0x2C, 0x1E, 0x2C, 0x1F, 0x2C, 0x20, 0x2C,
0x21, 0x2C, 0x22, 0x2C, 0x23, 0x2C, 0x24, 0x2C, 0x25, 0x2C, 0x26, 0x2C, 0x27, 0x2C, 0x28, 0x2C,
0x29, 0x2C, 0x2A, 0x2C, 0x2B, 0x2C, 0x2C, 0x2C, 0x2D, 0x2C, 0x2E, 0x2C, 0x5F, 0x2C, 0x60, 0x2C,
0x60, 0x2C, 0x62, 0x2C, 0x63, 0x2C, 0x64, 0x2C, 0x65, 0x2C, 0x66, 0x2C, 0x67, 0x2C, 0x67, 0x2C,
0x69, 0x2C, 0x69, 0x2C, 0x6B, 0x2C, 0x6B, 0x2C, 0x6D, 0x2C, 0x6E, 0x2C, 0x6F, 0x2C, 0x70, 0x2C,
0x71, 0x2C, 0x72, 0x2C, 0x73, 0x2C, 0x74, 0x2C, 0x75, 0x2C, 0x75, 0x2C, 0x77, 0x2C, 0x78, 0x2C,
0x79, 0x2C, 0x7A, 0x2C, 0x7B, 0x2C, 0x7C, 0x2C, 0x7D, 0x2C, 0x7E, 0x2C, 0x7F, 0x2C, 0x80, 0x2C,
0x80, 0x2C, 0x82, 0x2C, 0x82, 0x2C, 0x84, 0x2C, 0x84, 0x2C, 0x86, 0x2C, 0x86, 0x2C, 0x88, 0x2C,
0x88, 0x2C, 0x8A, 0x2C, 0x8A, 0x2C, 0x8C, 0x2C, 0x8C, 0x2C, 0x8E, 0x2C, 0x8E, 0x2C, 0x90, 0x2C,
0x90, 0x2C, 0x92, 0x2C, 0x92, 0x2C, 0x94, 0x2C, 0x94, 0x2C, 0x96, 0x2C, 0x96, 0x2C, 0x98, 0x2C,
0x98, 0x2C, 0x9A, 0x2C, 0x9A, 0x2C, 0x9C, 0x2C, 0x9C, 0x2C, 0x9E, 0x2C, 0x9E, 0x2C, 0xA0, 0x2C,
0xA0, 0x2C, 0xA2, 0x2C, 0xA2, 0x2C, 0xA4, 0x2C, 0xA4, 0x2C, 0xA6, 0x2C, 0xA6, 0x2C, 0xA8, 0x2C,
0xA8, 0x2C, 0xAA, 0x2C, 0xAA, 0x2C, 0xAC, 0x2C, 0xAC, 0x2C, 0xAE, 0x2C, 0xAE, 0x2C, 0xB0, 0x2C,
0xB0, 0x2C, 0xB2, 0x2C, 0xB2, 0x2C, 0xB4, 0x2C, 0xB4, 0x2C, 0xB6, 0x2C, 0xB6, 0x2C, 0xB8, 0x2C,
0xB8, 0x2C, 0xBA, 0x2C, 0xBA, 0x2C, 0xBC, 0x2C, 0xBC, 0x2C, 0xBE, 0x2C, 0xBE, 0x2C, 0xC0, 0x2C,
0xC0, 0x2C, 0xC2, 0x2C, 0xC2, 0x2C, 0xC4, 0x2C, 0xC4, 0x2C, 0xC6, 0x2C, 0xC6, 0x2C, 0xC8, 0x2C,
0xC8, 0x2C, 0xCA, 0x2C, 0xCA, 0x2C, 0xCC, 0x2C, 0xCC, 0x2C, 0xCE, 0x2C, 0xCE, 0x2C, 0xD0, 0x2C,
0xD0, 0x2C, 0xD2, 0x2C, 0xD2, 0x2C, 0xD4, 0x2C, 0xD4, 0x2C, 0xD6, 0x2C, 0xD6, 0x2C, 0xD8, 0x2C,
0xD8, 0x2C, 0xDA, 0x2C, 0xDA, 0x2C, 0xDC, 0x2C, 0xDC, 0x2C, 0xDE, 0x2C, 0xDE, 0x2C, 0xE0, 0x2C,
0xE0, 0x2C, 0xE2, 0x2C, 0xE2, 0x2C, 0xE4, 0x2C, 0xE5, 0x2C, 0xE6, 0x2C, 0xE7, 0x2C, 0xE8, 0x2C,
0xE9, 0x2C, 0xEA, 0x2C, 0xEB, 0x2C, 0xEC, 0x2C, 0xED, 0x2C, 0xEE, 0x2C, 0xEF, 0x2C, 0xF0, 0x2C,
0xF1, 0x2C, 0xF2, 0x2C, 0xF3, 0x2C, 0xF4, 0x2C, 0xF5, 0x2C, 0xF6, 0x2C, 0xF7, 0x2C, 0xF8, 0x2C,
0xF9, 0x2C, 0xFA, 0x2C, 0xFB, 0x2C, 0xFC, 0x2C, 0xFD, 0x2C, 0xFE, 0x2C, 0xFF, 0x2C, 0xA0, 0x10,
0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, 0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10,
0xA9, 0x10, 0xAA, 0x10, 0xAB, 0x10, 0xAC, 0x10, 0xAD, 0x10, 0xAE, 0x10, 0xAF, 0x10, 0xB0, 0x10,
0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10, 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10,
0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10, 0xBD, 0x10, 0xBE, 0x10, 0xBF, 0x10, 0xC0, 0x10,
0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xC5, 0x10, 0xFF, 0xFF, 0x1B, 0xD2, 0x21, 0xFF,
0x22, 0xFF, 0x23, 0xFF, 0x24, 0xFF, 0x25, 0xFF, 0x26, 0xFF, 0x27, 0xFF, 0x28, 0xFF, 0x29, 0xFF,
0x2A, 0xFF, 0x2B, 0xFF, 0x2C, 0xFF, 0x2D, 0xFF, 0x2E, 0xFF, 0x2F, 0xFF, 0x30, 0xFF, 0x31, 0xFF,
0x32, 0xFF, 0x33, 0xFF, 0x34, 0xFF, 0x35, 0xFF, 0x36, 0xFF, 0x37, 0xFF, 0x38, 0xFF, 0x39, 0xFF,
0x3A, 0xFF, 0x5B, 0xFF, 0x5C, 0xFF, 0x5D, 0xFF, 0x5E, 0xFF, 0x5F, 0xFF, 0x60, 0xFF, 0x61, 0xFF,
0x62, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0x65, 0xFF, 0x66, 0xFF, 0x67, 0xFF, 0x68, 0xFF, 0x69, 0xFF,
0x6A, 0xFF, 0x6B, 0xFF, 0x6C, 0xFF, 0x6D, 0xFF, 0x6E, 0xFF, 0x6F, 0xFF, 0x70, 0xFF, 0x71, 0xFF,
0x72, 0xFF, 0x73, 0xFF, 0x74, 0xFF, 0x75, 0xFF, 0x76, 0xFF, 0x77, 0xFF, 0x78, 0xFF, 0x79, 0xFF,
0x7A, 0xFF, 0x7B, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF, 0x7E, 0xFF, 0x7F, 0xFF, 0x80, 0xFF, 0x81, 0xFF,
0x82, 0xFF, 0x83, 0xFF, 0x84, 0xFF, 0x85, 0xFF, 0x86, 0xFF, 0x87, 0xFF, 0x88, 0xFF, 0x89, 0xFF,
0x8A, 0xFF, 0x8B, 0xFF, 0x8C, 0xFF, 0x8D, 0xFF, 0x8E, 0xFF, 0x8F, 0xFF, 0x90, 0xFF, 0x91, 0xFF,
0x92, 0xFF, 0x93, 0xFF, 0x94, 0xFF, 0x95, 0xFF, 0x96, 0xFF, 0x97, 0xFF, 0x98, 0xFF, 0x99, 0xFF,
0x9A, 0xFF, 0x9B, 0xFF, 0x9C, 0xFF, 0x9D, 0xFF, 0x9E, 0xFF, 0x9F, 0xFF, 0xA0, 0xFF, 0xA1, 0xFF,
0xA2, 0xFF, 0xA3, 0xFF, 0xA4, 0xFF, 0xA5, 0xFF, 0xA6, 0xFF, 0xA7, 0xFF, 0xA8, 0xFF, 0xA9, 0xFF,
0xAA, 0xFF, 0xAB, 0xFF, 0xAC, 0xFF, 0xAD, 0xFF, 0xAE, 0xFF, 0xAF, 0xFF, 0xB0, 0xFF, 0xB1, 0xFF,
0xB2, 0xFF, 0xB3, 0xFF, 0xB4, 0xFF, 0xB5, 0xFF, 0xB6, 0xFF, 0xB7, 0xFF, 0xB8, 0xFF, 0xB9, 0xFF,
0xBA, 0xFF, 0xBB, 0xFF, 0xBC, 0xFF, 0xBD, 0xFF, 0xBE, 0xFF, 0xBF, 0xFF, 0xC0, 0xFF, 0xC1, 0xFF,
0xC2, 0xFF, 0xC3, 0xFF, 0xC4, 0xFF, 0xC5, 0xFF, 0xC6, 0xFF, 0xC7, 0xFF, 0xC8, 0xFF, 0xC9, 0xFF,
0xCA, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF, 0xCE, 0xFF, 0xCF, 0xFF, 0xD0, 0xFF, 0xD1, 0xFF,
0xD2, 0xFF, 0xD3, 0xFF, 0xD4, 0xFF, 0xD5, 0xFF, 0xD6, 0xFF, 0xD7, 0xFF, 0xD8, 0xFF, 0xD9, 0xFF,
0xDA, 0xFF, 0xDB, 0xFF, 0xDC, 0xFF, 0xDD, 0xFF, 0xDE, 0xFF, 0xDF, 0xFF, 0xE0, 0xFF, 0xE1, 0xFF,
0xE2, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xE5, 0xFF, 0xE6, 0xFF, 0xE7, 0xFF, 0xE8, 0xFF, 0xE9, 0xFF,
0xEA, 0xFF, 0xEB, 0xFF, 0xEC, 0xFF, 0xED, 0xFF, 0xEE, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF,
0xF2, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF,
0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF
};
#endif /* _UPCASE_H */

View File

@ -1,11 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
*
* version.h: exFAT version definition
*/
#define EXFAT_BASE_VERSION "2.2.0"
#define EXFAT_EXTRAVERSION "3"
#define EXFAT_BASE_VERSION "5.8"
#define EXFAT_EXTRAVERSION "2"
#define EXFAT_VARIANT "arter97"
#define EXFAT_VERSION EXFAT_BASE_VERSION "-" EXFAT_EXTRAVERSION EXFAT_VARIANT

View File

@ -5,7 +5,7 @@
* xattr.c: exFAT code for supporting xattr(Extended File Attributes)
*/
#include "config.h"
#include "exfat_fs.h"
#ifdef CONFIG_EXFAT_VIRTUAL_XATTR
@ -13,7 +13,6 @@
#include <linux/fs.h>
#include <linux/xattr.h>
#include <linux/dcache.h>
#include "exfat.h"
#ifndef CONFIG_EXFAT_VIRTUAL_XATTR_SELINUX_LABEL
#define CONFIG_EXFAT_VIRTUAL_XATTR_SELINUX_LABEL ("undefined")
@ -52,7 +51,6 @@ ssize_t __exfat_getxattr(const char *name, void *value, size_t size)
return strlen(default_xattr);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
static int exfat_xattr_get(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size)
@ -68,7 +66,7 @@ static int exfat_xattr_set(const struct xattr_handler *handler,
return __exfat_xattr_check_support(name);
}
const struct xattr_handler exfat_xattr_handler = {
static const struct xattr_handler exfat_xattr_handler = {
.prefix = "", /* match anything */
.get = exfat_xattr_get,
.set = exfat_xattr_set,
@ -79,30 +77,4 @@ const struct xattr_handler *exfat_xattr_handlers[] = {
NULL
};
void setup_exfat_xattr_handler(struct super_block *sb)
{
sb->s_xattr = exfat_xattr_handlers;
}
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) */
int exfat_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
{
return __exfat_xattr_check_support(name);
}
ssize_t exfat_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
{
return __exfat_getxattr(name, value, size);
}
int exfat_removexattr(struct dentry *dentry, const char *name)
{
return __exfat_xattr_check_support(name);
}
void setup_exfat_xattr_handler(struct super_block *sb)
{
/* DO NOTHING */
}
#endif
#endif /* CONFIG_EXFAT_VIRTUAL_XATTR */