fs: exfat: sync with v5.8-1arter97
Signed-off-by: engstk <eng.stk@sapo.pt>
This commit is contained in:
parent
89c6789c19
commit
d24334a163
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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!
|
||||
|
265
fs/exfat/api.h
265
fs/exfat/api.h
@ -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
274
fs/exfat/balloc.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
994
fs/exfat/cache.c
994
fs/exfat/cache.c
File diff suppressed because it is too large
Load Diff
48
fs/exfat/compat.h
Normal file
48
fs/exfat/compat.h
Normal 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 */
|
@ -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 */
|
||||
|
3171
fs/exfat/core.c
3171
fs/exfat/core.c
File diff suppressed because it is too large
Load Diff
149
fs/exfat/core.h
149
fs/exfat/core.h
@ -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
@ -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.
|
||||
|
@ -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
1191
fs/exfat/dir.c
Normal file
File diff suppressed because it is too large
Load Diff
389
fs/exfat/exfat.h
389
fs/exfat/exfat.h
@ -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 */
|
||||
|
@ -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
165
fs/exfat/exfat_raw.h
Normal 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 */
|
@ -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;
|
||||
}
|
@ -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
403
fs/exfat/file.c
Normal 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
660
fs/exfat/inode.c
Normal 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);
|
||||
}
|
339
fs/exfat/misc.c
339
fs/exfat/misc.c
@ -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
1450
fs/exfat/namei.c
Normal file
File diff suppressed because it is too large
Load Diff
855
fs/exfat/nls.c
855
fs/exfat/nls.c
@ -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);
|
||||
}
|
||||
|
4239
fs/exfat/super.c
4239
fs/exfat/super.c
File diff suppressed because it is too large
Load Diff
@ -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 */
|
@ -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
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user