diff options
Diffstat (limited to 'drivers/staging/exfat')
-rw-r--r-- | drivers/staging/exfat/Kconfig | 41 | ||||
-rw-r--r-- | drivers/staging/exfat/Makefile | 10 | ||||
-rw-r--r-- | drivers/staging/exfat/TODO | 69 | ||||
-rw-r--r-- | drivers/staging/exfat/exfat.h | 824 | ||||
-rw-r--r-- | drivers/staging/exfat/exfat_blkdev.c | 136 | ||||
-rw-r--r-- | drivers/staging/exfat/exfat_cache.c | 555 | ||||
-rw-r--r-- | drivers/staging/exfat/exfat_core.c | 2582 | ||||
-rw-r--r-- | drivers/staging/exfat/exfat_nls.c | 212 | ||||
-rw-r--r-- | drivers/staging/exfat/exfat_super.c | 3883 | ||||
-rw-r--r-- | drivers/staging/exfat/exfat_upcase.c | 740 |
10 files changed, 0 insertions, 9052 deletions
diff --git a/drivers/staging/exfat/Kconfig b/drivers/staging/exfat/Kconfig deleted file mode 100644 index 292a19dfcaf5..000000000000 --- a/drivers/staging/exfat/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config STAGING_EXFAT_FS - tristate "exFAT fs support" - depends on BLOCK - select NLS - help - This adds support for the exFAT file system. - -config STAGING_EXFAT_DISCARD - bool "enable discard support" - depends on STAGING_EXFAT_FS - default y - -config STAGING_EXFAT_DELAYED_SYNC - bool "enable delayed sync" - depends on STAGING_EXFAT_FS - default n - -config STAGING_EXFAT_KERNEL_DEBUG - bool "enable kernel debug features via ioctl" - depends on STAGING_EXFAT_FS - default n - -config STAGING_EXFAT_DEBUG_MSG - bool "print debug messages" - depends on STAGING_EXFAT_FS - default n - -config STAGING_EXFAT_DEFAULT_CODEPAGE - int "Default codepage for exFAT" - default 437 - depends on STAGING_EXFAT_FS - help - This option should be set to the codepage of your exFAT filesystems. - -config STAGING_EXFAT_DEFAULT_IOCHARSET - string "Default iocharset for exFAT" - default "utf8" - depends on STAGING_EXFAT_FS - help - Set this to the default input/output character set you'd like exFAT to use. diff --git a/drivers/staging/exfat/Makefile b/drivers/staging/exfat/Makefile deleted file mode 100644 index 057556eeca0c..000000000000 --- a/drivers/staging/exfat/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later - -obj-$(CONFIG_STAGING_EXFAT_FS) += exfat.o - -exfat-y := exfat_core.o \ - exfat_super.o \ - exfat_blkdev.o \ - exfat_cache.o \ - exfat_nls.o \ - exfat_upcase.o diff --git a/drivers/staging/exfat/TODO b/drivers/staging/exfat/TODO deleted file mode 100644 index a283ce534cf4..000000000000 --- a/drivers/staging/exfat/TODO +++ /dev/null @@ -1,69 +0,0 @@ -A laundry list of things that need looking at, most of which will -require more work than the average checkpatch cleanup... - -Note that some of these entries may not be bugs - they're things -that need to be looked at, and *possibly* fixed. - -Clean up the ffsCamelCase function names. - -Fix (thing)->flags to not use magic numbers - multiple offenders - -Sort out all the s32/u32/u8 nonsense - most of these should be plain int. - -exfat_core.c - ffsReadFile - the goto err_out seem to leak a brelse(). -same for ffsWriteFile. - -All the calls to fs_sync() need to be looked at, particularly in the -context of EXFAT_DELAYED_SYNC. Currently, if that's defined, we only -flush to disk when sync() gets called. We should be doing at least -metadata flushes at appropriate times. - -ffsTruncateFile - if (old_size <= new_size) { -That doesn't look right. How did it ever work? Are they relying on lazy -block allocation when actual writes happen? If nothing else, it never -does the 'fid->size = new_size' and do the inode update.... - -ffsSetAttr() is just dangling in the breeze, not wired up at all... - -Convert global mutexes to a per-superblock mutex. - -Right now, we load exactly one UTF-8 table. Check to see -if that plays nice with different codepage and iocharset values -for simultanous mounts of different devices - -exfat_rmdir() checks for -EBUSY but ffsRemoveDir() doesn't return it. -In fact, there's a complete lack of -EBUSY testing anywhere. - -There's probably a few missing checks for -EEXIST - -check return codes of sync_dirty_buffer() - -Why is remove_file doing a num_entries++?? - -Double check a lot of can't-happen parameter checks (for null pointers for -things that have only one call site and can't pass a null, etc). - -All the DEBUG stuff can probably be tossed, including the ioctl(). Either -that, or convert to a proper fault-injection system. - -exfat_remount does exactly one thing. Fix to actually deal with remount -options, particularly handling R/O correctly. For that matter, allow -R/O mounts in the first place. - -Figure out why the VFAT code used multi_sector_(read|write) but the -exfat code doesn't use it. The difference matters on SSDs with wear leveling. - -exfat_fat_sync(), exfat_buf_sync(), and sync_alloc_bitmap() -aren't called anyplace.... - -Create helper function for exfat_set_entry_time() and exfat_set_entry_type() -because it's sort of ugly to be calling the same functionn directly and -other code calling through the fs_func struc ponters... - -clean up the remaining vol_type checks, which are of two types: -some are ?: operators with magic numbers, and the rest are places -where we're doing stuff with '.' and '..'. - -Patches to: - Greg Kroah-Hartman <gregkh@linuxfoundation.org> - Valdis Kletnieks <valdis.kletnieks@vt.edu> diff --git a/drivers/staging/exfat/exfat.h b/drivers/staging/exfat/exfat.h deleted file mode 100644 index 4d87360fab35..000000000000 --- a/drivers/staging/exfat/exfat.h +++ /dev/null @@ -1,824 +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/types.h> -#include <linux/buffer_head.h> - -#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG - /* For Debugging Purpose */ - /* IOCTL code 'f' used by - * - file systems typically #0~0x1F - * - embedded terminal devices #128~ - * - exts for debugging purpose #99 - * number 100 and 101 is available now but has possible conflicts - */ -#define EXFAT_IOC_GET_DEBUGFLAGS _IOR('f', 100, long) -#define EXFAT_IOC_SET_DEBUGFLAGS _IOW('f', 101, long) - -#define EXFAT_DEBUGFLAGS_INVALID_UMOUNT 0x01 -#define EXFAT_DEBUGFLAGS_ERROR_RW 0x02 -#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ - -#ifdef CONFIG_STAGING_EXFAT_DEBUG_MSG -#define DEBUG 1 -#else -#undef DEBUG -#endif - -#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ - -#define DENTRY_SIZE 32 /* dir entry size */ -#define DENTRY_SIZE_BITS 5 - -/* 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 - -/* 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 */ - -/* file types */ -#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 - -/* 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 CLUSTER_16(x) ((u16)(x)) -#define CLUSTER_32(x) ((u32)(x)) - -#define START_SECTOR(x) \ - ((((sector_t)((x) - 2)) << p_fs->sectors_per_clu_bits) + \ - p_fs->data_start_sector) - -#define IS_LAST_SECTOR_IN_CLUSTER(sec) \ - ((((sec) - p_fs->data_start_sector + 1) & \ - ((1 << p_fs->sectors_per_clu_bits) - 1)) == 0) - -#define GET_CLUSTER_FROM_SECTOR(sec) \ - ((u32)((((sec) - p_fs->data_start_sector) >> \ - p_fs->sectors_per_clu_bits) + 2)) - -#define GET16(p_src) \ - (((u16)(p_src)[0]) | (((u16)(p_src)[1]) << 8)) -#define GET32(p_src) \ - (((u32)(p_src)[0]) | (((u32)(p_src)[1]) << 8) | \ - (((u32)(p_src)[2]) << 16) | (((u32)(p_src)[3]) << 24)) -#define GET64(p_src) \ - (((u64)(p_src)[0]) | (((u64)(p_src)[1]) << 8) | \ - (((u64)(p_src)[2]) << 16) | (((u64)(p_src)[3]) << 24) | \ - (((u64)(p_src)[4]) << 32) | (((u64)(p_src)[5]) << 40) | \ - (((u64)(p_src)[6]) << 48) | (((u64)(p_src)[7]) << 56)) - -#define SET16(p_dst, src) \ - do { \ - (p_dst)[0] = (u8)(src); \ - (p_dst)[1] = (u8)(((u16)(src)) >> 8); \ - } while (0) -#define SET32(p_dst, src) \ - do { \ - (p_dst)[0] = (u8)(src); \ - (p_dst)[1] = (u8)(((u32)(src)) >> 8); \ - (p_dst)[2] = (u8)(((u32)(src)) >> 16); \ - (p_dst)[3] = (u8)(((u32)(src)) >> 24); \ - } while (0) -#define SET64(p_dst, src) \ - do { \ - (p_dst)[0] = (u8)(src); \ - (p_dst)[1] = (u8)(((u64)(src)) >> 8); \ - (p_dst)[2] = (u8)(((u64)(src)) >> 16); \ - (p_dst)[3] = (u8)(((u64)(src)) >> 24); \ - (p_dst)[4] = (u8)(((u64)(src)) >> 32); \ - (p_dst)[5] = (u8)(((u64)(src)) >> 40); \ - (p_dst)[6] = (u8)(((u64)(src)) >> 48); \ - (p_dst)[7] = (u8)(((u64)(src)) >> 56); \ - } while (0) - -#ifdef __LITTLE_ENDIAN -#define GET16_A(p_src) (*((u16 *)(p_src))) -#define GET32_A(p_src) (*((u32 *)(p_src))) -#define GET64_A(p_src) (*((u64 *)(p_src))) -#define SET16_A(p_dst, src) (*((u16 *)(p_dst)) = (u16)(src)) -#define SET32_A(p_dst, src) (*((u32 *)(p_dst)) = (u32)(src)) -#define SET64_A(p_dst, src) (*((u64 *)(p_dst)) = (u64)(src)) -#else /* BIG_ENDIAN */ -#define GET16_A(p_src) GET16(p_src) -#define GET32_A(p_src) GET32(p_src) -#define GET64_A(p_src) GET64(p_src) -#define SET16_A(p_dst, src) SET16(p_dst, src) -#define SET32_A(p_dst, src) SET32(p_dst, src) -#define SET64_A(p_dst, src) SET64(p_dst, src) -#endif - -/* 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 - -/* Upcase table macro */ -#define HIGH_INDEX_BIT (8) -#define HIGH_INDEX_MASK (0xFF00) -#define LOW_INDEX_BIT (16 - HIGH_INDEX_BIT) -#define UTBL_ROW_COUNT BIT(LOW_INDEX_BIT) -#define UTBL_COL_COUNT BIT(HIGH_INDEX_BIT) - -static inline u16 get_col_index(u16 i) -{ - return i >> LOW_INDEX_BIT; -} - -static inline u16 get_row_index(u16 i) -{ - return i & ~HIGH_INDEX_MASK; -} - -#define EXFAT_SUPER_MAGIC (0x2011BAB0L) -#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 */ - -/* file name lengths */ -#define MAX_CHARSET_SIZE 3 /* max size of multi-byte character */ -#define MAX_PATH_DEPTH 15 /* max depth of path name */ -#define MAX_NAME_LENGTH 256 /* max len of filename including NULL */ -#define MAX_PATH_LENGTH 260 /* max len of pathname including NULL */ -#define DOS_NAME_LENGTH 11 /* DOS filename length excluding NULL */ -#define DOS_PATH_LENGTH 80 /* DOS pathname length excluding NULL */ - -/* 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 0x000F -#define ATTR_RWMASK 0x007E - -/* file creation modes */ -#define FM_REGULAR 0x00 -#define FM_SYMLINK 0x40 - -#define NUM_UPCASE 2918 - -#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 - -struct date_time_t { - u16 Year; - u16 Month; - u16 Day; - u16 Hour; - u16 Minute; - u16 Second; - u16 MilliSecond; -}; - -struct part_info_t { - u32 Offset; /* start sector number of the partition */ - u32 Size; /* in sectors */ -}; - -struct dev_info_t { - u32 SecSize; /* sector size in bytes */ - u32 DevSize; /* block device size in sectors */ -}; - -struct vol_info_t { - u32 FatType; - u32 ClusterSize; - u32 NumClusters; - u32 FreeClusters; - u32 UsedClusters; -}; - -/* directory structure */ -struct chain_t { - u32 dir; - s32 size; - u8 flags; -}; - -struct file_id_t { - struct chain_t dir; - s32 entry; - u32 type; - u32 attr; - u32 start_clu; - u64 size; - u8 flags; - s64 rwoffset; - s32 hint_last_off; - u32 hint_last_clu; -}; - -struct dir_entry_t { - char Name[MAX_NAME_LENGTH * MAX_CHARSET_SIZE]; - - /* used only for FAT12/16/32, not used for exFAT */ - char ShortName[DOS_NAME_LENGTH + 2]; - - u32 Attr; - u64 Size; - u32 NumSubdirs; - struct date_time_t CreateTimestamp; - struct date_time_t ModifyTimestamp; - struct date_time_t AccessTimestamp; -}; - -struct timestamp_t { - 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) */ -}; - -/* MS_DOS FAT partition boot record (512 bytes) */ -struct pbr_sector_t { - u8 jmp_boot[3]; - u8 oem_name[8]; - u8 bpb[109]; - u8 boot_code[390]; - u8 signature[2]; -}; - -/* MS-DOS FAT12/16 BIOS parameter block (51 bytes) */ -struct bpb16_t { - u8 sector_size[2]; - u8 sectors_per_clu; - u8 num_reserved[2]; - u8 num_fats; - u8 num_root_entries[2]; - u8 num_sectors[2]; - u8 media_type; - u8 num_fat_sectors[2]; - u8 sectors_in_track[2]; - u8 num_heads[2]; - u8 num_hid_sectors[4]; - u8 num_huge_sectors[4]; - - u8 phy_drv_no; - u8 reserved; - u8 ext_signature; - u8 vol_serial[4]; - u8 vol_label[11]; - u8 vol_type[8]; -}; - -/* MS-DOS FAT32 BIOS parameter block (79 bytes) */ -struct bpb32_t { - u8 sector_size[2]; - u8 sectors_per_clu; - u8 num_reserved[2]; - u8 num_fats; - u8 num_root_entries[2]; - u8 num_sectors[2]; - u8 media_type; - u8 num_fat_sectors[2]; - u8 sectors_in_track[2]; - u8 num_heads[2]; - u8 num_hid_sectors[4]; - u8 num_huge_sectors[4]; - u8 num_fat32_sectors[4]; - u8 ext_flags[2]; - u8 fs_version[2]; - u8 root_cluster[4]; - u8 fsinfo_sector[2]; - u8 backup_sector[2]; - u8 reserved[12]; - - u8 phy_drv_no; - u8 ext_reserved; - u8 ext_signature; - u8 vol_serial[4]; - u8 vol_label[11]; - u8 vol_type[8]; -}; - -/* MS-DOS EXFAT BIOS parameter block (109 bytes) */ -struct bpbex_t { - u8 reserved1[53]; - u8 vol_offset[8]; - u8 vol_length[8]; - u8 fat_offset[4]; - u8 fat_length[4]; - u8 clu_offset[4]; - u8 clu_count[4]; - u8 root_cluster[4]; - u8 vol_serial[4]; - u8 fs_version[2]; - u8 vol_flags[2]; - u8 sector_size_bits; - u8 sectors_per_clu_bits; - u8 num_fats; - u8 phy_drv_no; - u8 perc_in_use; - u8 reserved2[7]; -}; - -/* MS-DOS FAT file system information sector (512 bytes) */ -struct fsi_sector_t { - u8 signature1[4]; - u8 reserved1[480]; - u8 signature2[4]; - u8 free_cluster[4]; - u8 next_cluster[4]; - u8 reserved2[14]; - u8 signature3[2]; -}; - -/* MS-DOS FAT directory entry (32 bytes) */ -struct dentry_t { - u8 dummy[32]; -}; - -struct dos_dentry_t { - u8 name[DOS_NAME_LENGTH]; - u8 attr; - u8 lcase; - u8 create_time_ms; - u8 create_time[2]; - u8 create_date[2]; - u8 access_date[2]; - u8 start_clu_hi[2]; - u8 modify_time[2]; - u8 modify_date[2]; - u8 start_clu_lo[2]; - u8 size[4]; -}; - -/* MS-DOS FAT extended directory entry (32 bytes) */ -struct ext_dentry_t { - u8 order; - u8 unicode_0_4[10]; - u8 attr; - u8 sysid; - u8 checksum; - u8 unicode_5_10[12]; - u8 start_clu[2]; - u8 unicode_11_12[4]; -}; - -/* MS-DOS EXFAT file directory entry (32 bytes) */ -struct file_dentry_t { - u8 type; - u8 num_ext; - u8 checksum[2]; - u8 attr[2]; - u8 reserved1[2]; - u8 create_time[2]; - u8 create_date[2]; - u8 modify_time[2]; - u8 modify_date[2]; - u8 access_time[2]; - u8 access_date[2]; - u8 create_time_ms; - u8 modify_time_ms; - u8 access_time_ms; - u8 reserved2[9]; -}; - -/* MS-DOS EXFAT stream extension directory entry (32 bytes) */ -struct strm_dentry_t { - u8 type; - u8 flags; - u8 reserved1; - u8 name_len; - u8 name_hash[2]; - u8 reserved2[2]; - u8 valid_size[8]; - u8 reserved3[4]; - u8 start_clu[4]; - u8 size[8]; -}; - -/* MS-DOS EXFAT file name directory entry (32 bytes) */ -struct name_dentry_t { - u8 type; - u8 flags; - u8 unicode_0_14[30]; -}; - -/* MS-DOS EXFAT allocation bitmap directory entry (32 bytes) */ -struct bmap_dentry_t { - u8 type; - u8 flags; - u8 reserved[18]; - u8 start_clu[4]; - u8 size[8]; -}; - -/* MS-DOS EXFAT up-case table directory entry (32 bytes) */ -struct case_dentry_t { - u8 type; - u8 reserved1[3]; - u8 checksum[4]; - u8 reserved2[12]; - u8 start_clu[4]; - u8 size[8]; -}; - -/* MS-DOS EXFAT volume label directory entry (32 bytes) */ -struct volm_dentry_t { - u8 type; - u8 label_len; - u8 unicode_0_10[22]; - u8 reserved[8]; -}; - -/* unused entry hint information */ -struct uentry_t { - u32 dir; - s32 entry; - struct chain_t clu; -}; - -/* DOS name structure */ -struct dos_name_t { - u8 name[DOS_NAME_LENGTH]; - u8 name_case; -}; - -/* unicode name structure */ -struct uni_name_t { - u16 name[MAX_NAME_LENGTH]; - u16 name_hash; - u8 name_len; -}; - -struct buf_cache_t { - struct buf_cache_t *next; - struct buf_cache_t *prev; - struct buf_cache_t *hash_next; - struct buf_cache_t *hash_prev; - s32 drv; - sector_t sec; - u32 flag; - struct buffer_head *buf_bh; -}; - -struct fs_info_t { - u32 drv; /* drive ID */ - u32 vol_type; /* volume FAT type */ - 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 sectors_per_clu; /* cluster size in sectors */ - u32 sectors_per_clu_bits; - - u32 PBR_sector; /* PBR sector */ - u32 FAT1_start_sector; /* FAT1 start sector */ - u32 FAT2_start_sector; /* FAT2 start sector */ - u32 root_start_sector; /* root dir start sector */ - u32 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; /* 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 */ - struct uentry_t hint_uentry; /* unused entry hint information */ - - u32 dev_ejected; /* block device operation error flag */ - - struct mutex v_mutex; - - /* FAT cache */ - struct buf_cache_t FAT_cache_array[FAT_CACHE_SIZE]; - struct buf_cache_t FAT_cache_lru_list; - struct buf_cache_t FAT_cache_hash_list[FAT_CACHE_HASH_SIZE]; - - /* buf cache */ - struct buf_cache_t buf_cache_array[BUF_CACHE_SIZE]; - struct buf_cache_t buf_cache_lru_list; - struct buf_cache_t buf_cache_hash_list[BUF_CACHE_HASH_SIZE]; -}; - -#define ES_2_ENTRIES 2 -#define ES_3_ENTRIES 3 -#define ES_ALL_ENTRIES 0 - -struct entry_set_cache_t { - /* sector number that contains file_entry */ - sector_t sector; - - /* byte offset in the sector */ - s32 offset; - - /* - * flag in stream entry. - * 01 for cluster chain, - * 03 for contig. clusteres. - */ - s32 alloc_flag; - - u32 num_entries; - - /* __buf should be the last member */ - void *__buf; -}; - -#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 */ - -/* ioctl command */ -#define EXFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32) - -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; - - /* codepage for shortname conversions */ - unsigned short codepage; - - /* charset for filename input/display */ - char *iocharset; - - unsigned char casesensitive; - - /* on error: continue, panic, remount-ro */ - unsigned char errors; -#ifdef CONFIG_STAGING_EXFAT_DISCARD - /* flag on if -o dicard specified and device support discard() */ - unsigned char discard; -#endif /* CONFIG_STAGING_EXFAT_DISCARD */ -}; - -#define EXFAT_HASH_BITS 8 -#define EXFAT_HASH_SIZE BIT(EXFAT_HASH_BITS) - -/* - * EXFAT file system in-core superblock data - */ -struct bd_info_t { - s32 sector_size; /* in bytes */ - s32 sector_size_bits; - s32 sector_size_mask; - - /* total number of sectors in this block device */ - s32 num_sectors; - - /* opened or not */ - bool opened; -}; - -struct exfat_sb_info { - struct fs_info_t fs_info; - struct bd_info_t bd_info; - - struct exfat_mount_options options; - - int s_dirt; - struct mutex s_lock; - struct nls_table *nls_disk; /* Codepage used on disk */ - struct nls_table *nls_io; /* Charset used for input and display */ - - struct inode *fat_inode; - - spinlock_t inode_hash_lock; - struct hlist_head inode_hashtable[EXFAT_HASH_SIZE]; -#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG - long debug_flags; -#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ -}; - -/* - * EXFAT file system inode data in memory - */ -struct exfat_inode_info { - struct file_id_t fid; - char *target; - /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */ - loff_t mmu_private; /* physically allocated size */ - loff_t i_pos; /* on-disk position of directory entry or 0 */ - struct hlist_node i_hash_fat; /* hash by i_location */ - struct rw_semaphore truncate_lock; - struct inode vfs_inode; - struct rw_semaphore i_alloc_sem; /* protect bmap against truncate */ -}; - -#define EXFAT_SB(sb) ((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); -} - -/* NLS management function */ -u16 nls_upper(struct super_block *sb, u16 a); -int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b); -void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, - struct uni_name_t *p_uniname); -void nls_cstring_to_uniname(struct super_block *sb, - struct uni_name_t *p_uniname, u8 *p_cstring, - bool *p_lossy); - -/* buffer cache management */ -void exfat_buf_init(struct super_block *sb); -void exfat_buf_shutdown(struct super_block *sb); -int exfat_fat_read(struct super_block *sb, u32 loc, u32 *content); -s32 exfat_fat_write(struct super_block *sb, u32 loc, u32 content); -u8 *exfat_fat_getblk(struct super_block *sb, sector_t sec); -void exfat_fat_modify(struct super_block *sb, sector_t sec); -void exfat_fat_release_all(struct super_block *sb); -void exfat_fat_sync(struct super_block *sb); -u8 *exfat_buf_getblk(struct super_block *sb, sector_t sec); -void exfat_buf_modify(struct super_block *sb, sector_t sec); -void exfat_buf_lock(struct super_block *sb, sector_t sec); -void exfat_buf_unlock(struct super_block *sb, sector_t sec); -void exfat_buf_release(struct super_block *sb, sector_t sec); -void exfat_buf_release_all(struct super_block *sb); -void exfat_buf_sync(struct super_block *sb); - -/* fs management functions */ -void fs_set_vol_flags(struct super_block *sb, u32 new_flag); -void fs_error(struct super_block *sb); - -/* cluster management functions */ -s32 count_num_clusters(struct super_block *sb, struct chain_t *dir); -void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len); - -/* allocation bitmap management functions */ -s32 load_alloc_bitmap(struct super_block *sb); -void free_alloc_bitmap(struct super_block *sb); -void sync_alloc_bitmap(struct super_block *sb); - -/* upcase table management functions */ -s32 load_upcase_table(struct super_block *sb); -void free_upcase_table(struct super_block *sb); - -/* dir entry management functions */ -struct timestamp_t *tm_current(struct timestamp_t *tm); - -struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir, - s32 entry, sector_t *sector); -struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb, - struct chain_t *p_dir, s32 entry, - u32 type, - struct dentry_t **file_ep); -void release_entry_set(struct entry_set_cache_t *es); -s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir, - u32 type); -void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir, - s32 entry); -void update_dir_checksum_with_entry_set(struct super_block *sb, - struct entry_set_cache_t *es); -bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir); - -/* name conversion functions */ -s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir, - struct uni_name_t *p_uniname, s32 *entries, - struct dos_name_t *p_dosname); -u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type); - -/* name resolution functions */ -s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir, - struct uni_name_t *p_uniname); - -/* file operation functions */ -s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr); -s32 create_dir(struct inode *inode, struct chain_t *p_dir, - struct uni_name_t *p_uniname, struct file_id_t *fid); -s32 create_file(struct inode *inode, struct chain_t *p_dir, - struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid); -void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry); -s32 exfat_rename_file(struct inode *inode, struct chain_t *p_dir, s32 old_entry, - struct uni_name_t *p_uniname, struct file_id_t *fid); -s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry, - struct chain_t *p_newdir, struct uni_name_t *p_uniname, - struct file_id_t *fid); - -/* sector read/write functions */ -int sector_read(struct super_block *sb, sector_t sec, - struct buffer_head **bh, bool read); -int sector_write(struct super_block *sb, sector_t sec, - struct buffer_head *bh, bool sync); -int multi_sector_read(struct super_block *sb, sector_t sec, - struct buffer_head **bh, s32 num_secs, bool read); -int multi_sector_write(struct super_block *sb, sector_t sec, - struct buffer_head *bh, s32 num_secs, bool sync); - -void exfat_bdev_open(struct super_block *sb); -void exfat_bdev_close(struct super_block *sb); -int exfat_bdev_read(struct super_block *sb, sector_t secno, - struct buffer_head **bh, u32 num_secs, bool read); -int exfat_bdev_write(struct super_block *sb, sector_t secno, - struct buffer_head *bh, u32 num_secs, bool sync); -int exfat_bdev_sync(struct super_block *sb); - -/* cluster operation functions */ -s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, - struct chain_t *p_chain); -void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain, - s32 do_relse); -s32 exfat_count_used_clusters(struct super_block *sb); - -/* dir operation functions */ -s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir, - struct uni_name_t *p_uniname, s32 num_entries, - struct dos_name_t *p_dosname, u32 type); -void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, - s32 entry, s32 order, s32 num_entries); -void exfat_get_uni_name_from_ext_entry(struct super_block *sb, - struct chain_t *p_dir, s32 entry, - u16 *uniname); -s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, - s32 entry, struct dentry_t *p_entry); -s32 exfat_calc_num_entries(struct uni_name_t *p_uniname); - -/* dir entry getter/setter */ -u32 exfat_get_entry_type(struct dentry_t *p_entry); -u32 exfat_get_entry_attr(struct dentry_t *p_entry); -void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr); -u8 exfat_get_entry_flag(struct dentry_t *p_entry); -void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flags); -u32 exfat_get_entry_clu0(struct dentry_t *p_entry); -void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu); -u64 exfat_get_entry_size(struct dentry_t *p_entry); -void exfat_set_entry_size(struct dentry_t *p_entry, u64 size); -void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, - u8 mode); -void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, - u8 mode); - -extern const u8 uni_upcase[]; -#endif /* _EXFAT_H */ diff --git a/drivers/staging/exfat/exfat_blkdev.c b/drivers/staging/exfat/exfat_blkdev.c deleted file mode 100644 index 0a3dc3568293..000000000000 --- a/drivers/staging/exfat/exfat_blkdev.c +++ /dev/null @@ -1,136 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. - */ - -#include <linux/blkdev.h> -#include <linux/buffer_head.h> -#include <linux/fs.h> -#include "exfat.h" - -void exfat_bdev_open(struct super_block *sb) -{ - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - if (p_bd->opened) - return; - - p_bd->sector_size = bdev_logical_block_size(sb->s_bdev); - p_bd->sector_size_bits = ilog2(p_bd->sector_size); - p_bd->sector_size_mask = p_bd->sector_size - 1; - p_bd->num_sectors = i_size_read(sb->s_bdev->bd_inode) >> - p_bd->sector_size_bits; - p_bd->opened = true; -} - -void exfat_bdev_close(struct super_block *sb) -{ - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - p_bd->opened = false; -} - -int exfat_bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh, - u32 num_secs, bool read) -{ - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG - struct exfat_sb_info *sbi = EXFAT_SB(sb); - long flags = sbi->debug_flags; - - if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) - return -EIO; -#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ - - if (!p_bd->opened) - return -ENODEV; - - if (*bh) - __brelse(*bh); - - if (read) - *bh = __bread(sb->s_bdev, secno, - num_secs << p_bd->sector_size_bits); - else - *bh = __getblk(sb->s_bdev, secno, - num_secs << p_bd->sector_size_bits); - - if (*bh) - return 0; - - WARN(!p_fs->dev_ejected, - "[EXFAT] No bh, device seems wrong or to be ejected.\n"); - - return -EIO; -} - -int exfat_bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, - u32 num_secs, bool sync) -{ - s32 count; - struct buffer_head *bh2; - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); -#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG - struct exfat_sb_info *sbi = EXFAT_SB(sb); - long flags = sbi->debug_flags; - - if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) - return -EIO; -#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ - - if (!p_bd->opened) - return -ENODEV; - - if (secno == bh->b_blocknr) { - lock_buffer(bh); - set_buffer_uptodate(bh); - mark_buffer_dirty(bh); - unlock_buffer(bh); - if (sync && (sync_dirty_buffer(bh) != 0)) - return -EIO; - } else { - count = num_secs << p_bd->sector_size_bits; - - bh2 = __getblk(sb->s_bdev, 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: - WARN(!p_fs->dev_ejected, - "[EXFAT] No bh, device seems wrong or to be ejected.\n"); - - return -EIO; -} - -int exfat_bdev_sync(struct super_block *sb) -{ - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); -#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG - struct exfat_sb_info *sbi = EXFAT_SB(sb); - long flags = sbi->debug_flags; - - if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) - return -EIO; -#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ - - if (!p_bd->opened) - return -ENODEV; - - return sync_blockdev(sb->s_bdev); -} diff --git a/drivers/staging/exfat/exfat_cache.c b/drivers/staging/exfat/exfat_cache.c deleted file mode 100644 index 3fd5604058a9..000000000000 --- a/drivers/staging/exfat/exfat_cache.c +++ /dev/null @@ -1,555 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. - */ - -#include <linux/buffer_head.h> -#include <linux/fs.h> -#include <linux/mutex.h> -#include "exfat.h" - -#define LOCKBIT 0x01 -#define DIRTYBIT 0x02 - -/* Local variables */ -static DEFINE_MUTEX(f_mutex); -static DEFINE_MUTEX(b_mutex); - -static struct buf_cache_t *FAT_cache_find(struct super_block *sb, sector_t sec) -{ - s32 off; - struct buf_cache_t *bp, *hp; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - off = (sec + - (sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE - 1); - - hp = &p_fs->FAT_cache_hash_list[off]; - for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { - if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { - WARN(!bp->buf_bh, - "[EXFAT] FAT_cache has no bh. It will make system panic.\n"); - - touch_buffer(bp->buf_bh); - return bp; - } - } - return NULL; -} - -static void push_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list) -{ - bp->next = list->next; - bp->prev = list; - list->next->prev = bp; - list->next = bp; -} - -static void push_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list) -{ - bp->prev = list->prev; - bp->next = list; - list->prev->next = bp; - list->prev = bp; -} - -static void move_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list) -{ - bp->prev->next = bp->next; - bp->next->prev = bp->prev; - push_to_mru(bp, list); -} - -static void move_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list) -{ - bp->prev->next = bp->next; - bp->next->prev = bp->prev; - push_to_lru(bp, list); -} - -static struct buf_cache_t *FAT_cache_get(struct super_block *sb, sector_t sec) -{ - struct buf_cache_t *bp; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - bp = p_fs->FAT_cache_lru_list.prev; - - move_to_mru(bp, &p_fs->FAT_cache_lru_list); - return bp; -} - -static void FAT_cache_insert_hash(struct super_block *sb, - struct buf_cache_t *bp) -{ - s32 off; - struct buf_cache_t *hp; - struct fs_info_t *p_fs; - - p_fs = &(EXFAT_SB(sb)->fs_info); - off = (bp->sec + - (bp->sec >> p_fs->sectors_per_clu_bits)) & - (FAT_CACHE_HASH_SIZE - 1); - - hp = &p_fs->FAT_cache_hash_list[off]; - bp->hash_next = hp->hash_next; - bp->hash_prev = hp; - hp->hash_next->hash_prev = bp; - hp->hash_next = bp; -} - -static void FAT_cache_remove_hash(struct buf_cache_t *bp) -{ - (bp->hash_prev)->hash_next = bp->hash_next; - (bp->hash_next)->hash_prev = bp->hash_prev; -} - -static void buf_cache_insert_hash(struct super_block *sb, - struct buf_cache_t *bp) -{ - s32 off; - struct buf_cache_t *hp; - struct fs_info_t *p_fs; - - p_fs = &(EXFAT_SB(sb)->fs_info); - off = (bp->sec + - (bp->sec >> p_fs->sectors_per_clu_bits)) & - (BUF_CACHE_HASH_SIZE - 1); - - hp = &p_fs->buf_cache_hash_list[off]; - bp->hash_next = hp->hash_next; - bp->hash_prev = hp; - hp->hash_next->hash_prev = bp; - hp->hash_next = bp; -} - -static void buf_cache_remove_hash(struct buf_cache_t *bp) -{ - (bp->hash_prev)->hash_next = bp->hash_next; - (bp->hash_next)->hash_prev = bp->hash_prev; -} - -void exfat_buf_init(struct super_block *sb) -{ - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - int i; - - /* LRU list */ - p_fs->FAT_cache_lru_list.next = &p_fs->FAT_cache_lru_list; - p_fs->FAT_cache_lru_list.prev = &p_fs->FAT_cache_lru_list; - - for (i = 0; i < FAT_CACHE_SIZE; i++) { - p_fs->FAT_cache_array[i].drv = -1; - p_fs->FAT_cache_array[i].sec = ~0; - p_fs->FAT_cache_array[i].flag = 0; - p_fs->FAT_cache_array[i].buf_bh = NULL; - p_fs->FAT_cache_array[i].prev = NULL; - p_fs->FAT_cache_array[i].next = NULL; - push_to_mru(&p_fs->FAT_cache_array[i], - &p_fs->FAT_cache_lru_list); - } - - p_fs->buf_cache_lru_list.next = &p_fs->buf_cache_lru_list; - p_fs->buf_cache_lru_list.prev = &p_fs->buf_cache_lru_list; - - for (i = 0; i < BUF_CACHE_SIZE; i++) { - p_fs->buf_cache_array[i].drv = -1; - p_fs->buf_cache_array[i].sec = ~0; - p_fs->buf_cache_array[i].flag = 0; - p_fs->buf_cache_array[i].buf_bh = NULL; - p_fs->buf_cache_array[i].prev = NULL; - p_fs->buf_cache_array[i].next = NULL; - push_to_mru(&p_fs->buf_cache_array[i], - &p_fs->buf_cache_lru_list); - } - - /* HASH list */ - for (i = 0; i < FAT_CACHE_HASH_SIZE; i++) { - p_fs->FAT_cache_hash_list[i].drv = -1; - p_fs->FAT_cache_hash_list[i].sec = ~0; - p_fs->FAT_cache_hash_list[i].hash_next = - &p_fs->FAT_cache_hash_list[i]; - p_fs->FAT_cache_hash_list[i].hash_prev = - &p_fs->FAT_cache_hash_list[i]; - } - - for (i = 0; i < FAT_CACHE_SIZE; i++) - FAT_cache_insert_hash(sb, &p_fs->FAT_cache_array[i]); - - for (i = 0; i < BUF_CACHE_HASH_SIZE; i++) { - p_fs->buf_cache_hash_list[i].drv = -1; - p_fs->buf_cache_hash_list[i].sec = ~0; - p_fs->buf_cache_hash_list[i].hash_next = - &p_fs->buf_cache_hash_list[i]; - p_fs->buf_cache_hash_list[i].hash_prev = - &p_fs->buf_cache_hash_list[i]; - } - - for (i = 0; i < BUF_CACHE_SIZE; i++) - buf_cache_insert_hash(sb, &p_fs->buf_cache_array[i]); -} - -void exfat_buf_shutdown(struct super_block *sb) -{ -} - -static int __exfat_fat_read(struct super_block *sb, u32 loc, u32 *content) -{ - s32 off; - u32 _content; - sector_t sec; - u8 *fat_sector, *fat_entry; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - sec = p_fs->FAT1_start_sector + - (loc >> (p_bd->sector_size_bits - 2)); - off = (loc << 2) & p_bd->sector_size_mask; - - fat_sector = exfat_fat_getblk(sb, sec); - if (!fat_sector) - return -1; - - fat_entry = &fat_sector[off]; - _content = GET32_A(fat_entry); - - if (_content >= CLUSTER_32(0xFFFFFFF8)) { - *content = CLUSTER_32(~0); - return 0; - } - *content = CLUSTER_32(_content); - return 0; -} - -/* in : sb, loc - * out: content - * returns 0 on success - * -1 on error - */ -int exfat_fat_read(struct super_block *sb, u32 loc, u32 *content) -{ - s32 ret; - - mutex_lock(&f_mutex); - ret = __exfat_fat_read(sb, loc, content); - mutex_unlock(&f_mutex); - - return ret; -} - -static s32 __exfat_fat_write(struct super_block *sb, u32 loc, u32 content) -{ - s32 off; - sector_t sec; - u8 *fat_sector, *fat_entry; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - sec = p_fs->FAT1_start_sector + (loc >> - (p_bd->sector_size_bits - 2)); - off = (loc << 2) & p_bd->sector_size_mask; - - fat_sector = exfat_fat_getblk(sb, sec); - if (!fat_sector) - return -1; - - fat_entry = &fat_sector[off]; - - SET32_A(fat_entry, content); - - exfat_fat_modify(sb, sec); - return 0; -} - -int exfat_fat_write(struct super_block *sb, u32 loc, u32 content) -{ - s32 ret; - - mutex_lock(&f_mutex); - ret = __exfat_fat_write(sb, loc, content); - mutex_unlock(&f_mutex); - - return ret; -} - -u8 *exfat_fat_getblk(struct super_block *sb, sector_t sec) -{ - struct buf_cache_t *bp; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - bp = FAT_cache_find(sb, sec); - if (bp) { - move_to_mru(bp, &p_fs->FAT_cache_lru_list); - return bp->buf_bh->b_data; - } - - bp = FAT_cache_get(sb, sec); - - FAT_cache_remove_hash(bp); - - bp->drv = p_fs->drv; - bp->sec = sec; - bp->flag = 0; - - FAT_cache_insert_hash(sb, bp); - - if (sector_read(sb, sec, &bp->buf_bh, 1) != 0) { - FAT_cache_remove_hash(bp); - bp->drv = -1; - bp->sec = ~0; - bp->flag = 0; - bp->buf_bh = NULL; - - move_to_lru(bp, &p_fs->FAT_cache_lru_list); - return NULL; - } - - return bp->buf_bh->b_data; -} - -void exfat_fat_modify(struct super_block *sb, sector_t sec) -{ - struct buf_cache_t *bp; - - bp = FAT_cache_find(sb, sec); - if (bp) - sector_write(sb, sec, bp->buf_bh, 0); -} - -void exfat_fat_release_all(struct super_block *sb) -{ - struct buf_cache_t *bp; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - mutex_lock(&f_mutex); - - bp = p_fs->FAT_cache_lru_list.next; - while (bp != &p_fs->FAT_cache_lru_list) { - if (bp->drv == p_fs->drv) { - bp->drv = -1; - bp->sec = ~0; - bp->flag = 0; - - if (bp->buf_bh) { - __brelse(bp->buf_bh); - bp->buf_bh = NULL; - } - } - bp = bp->next; - } - - mutex_unlock(&f_mutex); -} - -void exfat_fat_sync(struct super_block *sb) -{ - struct buf_cache_t *bp; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - mutex_lock(&f_mutex); - - bp = p_fs->FAT_cache_lru_list.next; - while (bp != &p_fs->FAT_cache_lru_list) { - if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { - sync_dirty_buffer(bp->buf_bh); - bp->flag &= ~(DIRTYBIT); - } - bp = bp->next; - } - - mutex_unlock(&f_mutex); -} - -static struct buf_cache_t *buf_cache_find(struct super_block *sb, sector_t sec) -{ - s32 off; - struct buf_cache_t *bp, *hp; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - off = (sec + (sec >> p_fs->sectors_per_clu_bits)) & - (BUF_CACHE_HASH_SIZE - 1); - - hp = &p_fs->buf_cache_hash_list[off]; - for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { - if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { - touch_buffer(bp->buf_bh); - return bp; - } - } - return NULL; -} - -static struct buf_cache_t *buf_cache_get(struct super_block *sb, sector_t sec) -{ - struct buf_cache_t *bp; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - bp = p_fs->buf_cache_lru_list.prev; - while (bp->flag & LOCKBIT) - bp = bp->prev; - - move_to_mru(bp, &p_fs->buf_cache_lru_list); - return bp; -} - -static u8 *__exfat_buf_getblk(struct super_block *sb, sector_t sec) -{ - struct buf_cache_t *bp; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - bp = buf_cache_find(sb, sec); - if (bp) { - move_to_mru(bp, &p_fs->buf_cache_lru_list); - return bp->buf_bh->b_data; - } - - bp = buf_cache_get(sb, sec); - - buf_cache_remove_hash(bp); - - bp->drv = p_fs->drv; - bp->sec = sec; - bp->flag = 0; - - buf_cache_insert_hash(sb, bp); - - if (sector_read(sb, sec, &bp->buf_bh, 1) != 0) { - buf_cache_remove_hash(bp); - bp->drv = -1; - bp->sec = ~0; - bp->flag = 0; - bp->buf_bh = NULL; - - move_to_lru(bp, &p_fs->buf_cache_lru_list); - return NULL; - } - - return bp->buf_bh->b_data; -} - -u8 *exfat_buf_getblk(struct super_block *sb, sector_t sec) -{ - u8 *buf; - - mutex_lock(&b_mutex); - buf = __exfat_buf_getblk(sb, sec); - mutex_unlock(&b_mutex); - - return buf; -} - -void exfat_buf_modify(struct super_block *sb, sector_t sec) -{ - struct buf_cache_t *bp; - - mutex_lock(&b_mutex); - - bp = buf_cache_find(sb, sec); - if (likely(bp)) - sector_write(sb, sec, bp->buf_bh, 0); - - WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", - (unsigned long long)sec); - - mutex_unlock(&b_mutex); -} - -void exfat_buf_lock(struct super_block *sb, sector_t sec) -{ - struct buf_cache_t *bp; - - mutex_lock(&b_mutex); - - bp = buf_cache_find(sb, sec); - if (likely(bp)) - bp->flag |= LOCKBIT; - - WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", - (unsigned long long)sec); - - mutex_unlock(&b_mutex); -} - -void exfat_buf_unlock(struct super_block *sb, sector_t sec) -{ - struct buf_cache_t *bp; - - mutex_lock(&b_mutex); - - bp = buf_cache_find(sb, sec); - if (likely(bp)) - bp->flag &= ~(LOCKBIT); - - WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", - (unsigned long long)sec); - - mutex_unlock(&b_mutex); -} - -void exfat_buf_release(struct super_block *sb, sector_t sec) -{ - struct buf_cache_t *bp; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - mutex_lock(&b_mutex); - - bp = buf_cache_find(sb, sec); - if (likely(bp)) { - bp->drv = -1; - bp->sec = ~0; - bp->flag = 0; - - if (bp->buf_bh) { - __brelse(bp->buf_bh); - bp->buf_bh = NULL; - } - - move_to_lru(bp, &p_fs->buf_cache_lru_list); - } - - mutex_unlock(&b_mutex); -} - -void exfat_buf_release_all(struct super_block *sb) -{ - struct buf_cache_t *bp; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - mutex_lock(&b_mutex); - - bp = p_fs->buf_cache_lru_list.next; - while (bp != &p_fs->buf_cache_lru_list) { - if (bp->drv == p_fs->drv) { - bp->drv = -1; - bp->sec = ~0; - bp->flag = 0; - - if (bp->buf_bh) { - __brelse(bp->buf_bh); - bp->buf_bh = NULL; - } - } - bp = bp->next; - } - - mutex_unlock(&b_mutex); -} - -void exfat_buf_sync(struct super_block *sb) -{ - struct buf_cache_t *bp; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - mutex_lock(&b_mutex); - - bp = p_fs->buf_cache_lru_list.next; - while (bp != &p_fs->buf_cache_lru_list) { - if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { - sync_dirty_buffer(bp->buf_bh); - bp->flag &= ~(DIRTYBIT); - } - bp = bp->next; - } - - mutex_unlock(&b_mutex); -} diff --git a/drivers/staging/exfat/exfat_core.c b/drivers/staging/exfat/exfat_core.c deleted file mode 100644 index 07b460d01334..000000000000 --- a/drivers/staging/exfat/exfat_core.c +++ /dev/null @@ -1,2582 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. - */ - -#include <linux/types.h> -#include <linux/buffer_head.h> -#include <linux/fs.h> -#include <linux/mutex.h> -#include <linux/blkdev.h> -#include <linux/slab.h> -#include "exfat.h" - -static void __set_sb_dirty(struct super_block *sb) -{ - struct exfat_sb_info *sbi = EXFAT_SB(sb); - - sbi->s_dirt = 1; -} - -static u8 name_buf[MAX_PATH_LENGTH * MAX_CHARSET_SIZE]; - -static u8 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 u8 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 */ -}; - -#define BITMAP_LOC(v) ((v) >> 3) -#define BITMAP_SHIFT(v) ((v) & 0x07) - -static inline s32 exfat_bitmap_test(u8 *bitmap, int i) -{ - u8 data; - - data = bitmap[BITMAP_LOC(i)]; - if ((data >> BITMAP_SHIFT(i)) & 0x01) - return 1; - return 0; -} - -static inline void exfat_bitmap_set(u8 *bitmap, int i) -{ - bitmap[BITMAP_LOC(i)] |= (0x01 << BITMAP_SHIFT(i)); -} - -static inline void exfat_bitmap_clear(u8 *bitmap, int i) -{ - bitmap[BITMAP_LOC(i)] &= ~(0x01 << BITMAP_SHIFT(i)); -} - -/* - * File System Management Functions - */ - -void fs_set_vol_flags(struct super_block *sb, u32 new_flag) -{ - struct pbr_sector_t *p_pbr; - struct bpbex_t *p_bpb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if (p_fs->vol_flag == new_flag) - return; - - p_fs->vol_flag = new_flag; - - if (!p_fs->pbr_bh) { - if (sector_read(sb, p_fs->PBR_sector, - &p_fs->pbr_bh, 1) != 0) - return; - } - - p_pbr = (struct pbr_sector_t *)p_fs->pbr_bh->b_data; - p_bpb = (struct bpbex_t *)p_pbr->bpb; - SET16(p_bpb->vol_flags, (u16)new_flag); - - /* XXX duyoung - * what can we do here? (cuz fs_set_vol_flags() is void) - */ - if ((new_flag == VOL_DIRTY) && (!buffer_dirty(p_fs->pbr_bh))) - sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 1); - else - sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 0); -} - -void fs_error(struct super_block *sb) -{ - struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; - - if (opts->errors == EXFAT_ERRORS_PANIC) { - panic("[EXFAT] Filesystem panic from previous error\n"); - } else if ((opts->errors == EXFAT_ERRORS_RO) && !sb_rdonly(sb)) { - sb->s_flags |= SB_RDONLY; - pr_err("[EXFAT] Filesystem has been set read-only\n"); - } -} - -/* - * Cluster Management Functions - */ - -static s32 clear_cluster(struct super_block *sb, u32 clu) -{ - sector_t s, n; - s32 ret = 0; - struct buffer_head *tmp_bh = NULL; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - if (clu == CLUSTER_32(0)) { /* FAT16 root_dir */ - s = p_fs->root_start_sector; - n = p_fs->data_start_sector; - } else { - s = START_SECTOR(clu); - n = s + p_fs->sectors_per_clu; - } - - for (; s < n; s++) { - ret = sector_read(sb, s, &tmp_bh, 0); - if (ret != 0) - return ret; - - memset((char *)tmp_bh->b_data, 0x0, p_bd->sector_size); - ret = sector_write(sb, s, tmp_bh, 0); - if (ret != 0) - break; - } - - brelse(tmp_bh); - return ret; -} - -static s32 set_alloc_bitmap(struct super_block *sb, u32 clu) -{ - int i, b; - sector_t sector; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - i = clu >> (p_bd->sector_size_bits + 3); - b = clu & ((p_bd->sector_size << 3) - 1); - - sector = START_SECTOR(p_fs->map_clu) + i; - - exfat_bitmap_set((u8 *)p_fs->vol_amap[i]->b_data, b); - - return sector_write(sb, sector, p_fs->vol_amap[i], 0); -} - -static s32 clr_alloc_bitmap(struct super_block *sb, u32 clu) -{ - int i, b; - sector_t sector; -#ifdef CONFIG_STAGING_EXFAT_DISCARD - struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct exfat_mount_options *opts = &sbi->options; - int ret; -#endif /* CONFIG_STAGING_EXFAT_DISCARD */ - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - i = clu >> (p_bd->sector_size_bits + 3); - b = clu & ((p_bd->sector_size << 3) - 1); - - sector = START_SECTOR(p_fs->map_clu) + i; - - exfat_bitmap_clear((u8 *)p_fs->vol_amap[i]->b_data, b); - -#ifdef CONFIG_STAGING_EXFAT_DISCARD - if (opts->discard) { - ret = sb_issue_discard(sb, START_SECTOR(clu), - (1 << p_fs->sectors_per_clu_bits), - GFP_NOFS, 0); - if (ret == -EOPNOTSUPP) { - pr_warn("discard not supported by device, disabling"); - opts->discard = 0; - } else { - return ret; - } - } -#endif /* CONFIG_STAGING_EXFAT_DISCARD */ - - return sector_write(sb, sector, p_fs->vol_amap[i], 0); -} - -static u32 test_alloc_bitmap(struct super_block *sb, u32 clu) -{ - int i, map_i, map_b; - u32 clu_base, clu_free; - u8 k, clu_mask; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - clu_base = (clu & ~(0x7)) + 2; - clu_mask = (1 << (clu - clu_base + 2)) - 1; - - map_i = clu >> (p_bd->sector_size_bits + 3); - map_b = (clu >> 3) & p_bd->sector_size_mask; - - for (i = 2; i < p_fs->num_clusters; i += 8) { - k = *(((u8 *)p_fs->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 < p_fs->num_clusters) - return clu_free; - } - clu_base += 8; - - if (((++map_b) >= p_bd->sector_size) || - (clu_base >= p_fs->num_clusters)) { - if ((++map_i) >= p_fs->map_sectors) { - clu_base = 2; - map_i = 0; - } - map_b = 0; - } - } - - return CLUSTER_32(~0); -} - -s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, - struct chain_t *p_chain) -{ - s32 num_clusters = 0; - u32 hint_clu, new_clu, last_clu = CLUSTER_32(~0); - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - hint_clu = p_chain->dir; - if (hint_clu == CLUSTER_32(~0)) { - hint_clu = test_alloc_bitmap(sb, p_fs->clu_srch_ptr - 2); - if (hint_clu == CLUSTER_32(~0)) - return 0; - } else if (hint_clu >= p_fs->num_clusters) { - hint_clu = 2; - p_chain->flags = 0x01; - } - - __set_sb_dirty(sb); - - p_chain->dir = CLUSTER_32(~0); - - while ((new_clu = test_alloc_bitmap(sb, hint_clu - 2)) != CLUSTER_32(~0)) { - if (new_clu != hint_clu) { - if (p_chain->flags == 0x03) { - exfat_chain_cont_cluster(sb, p_chain->dir, - num_clusters); - p_chain->flags = 0x01; - } - } - - if (set_alloc_bitmap(sb, new_clu - 2) != 0) - return -EIO; - - num_clusters++; - - if (p_chain->flags == 0x01) { - if (exfat_fat_write(sb, new_clu, CLUSTER_32(~0)) < 0) - return -EIO; - } - - if (p_chain->dir == CLUSTER_32(~0)) { - p_chain->dir = new_clu; - } else { - if (p_chain->flags == 0x01) { - if (exfat_fat_write(sb, last_clu, new_clu) < 0) - return -EIO; - } - } - last_clu = new_clu; - - if ((--num_alloc) == 0) { - p_fs->clu_srch_ptr = hint_clu; - if (p_fs->used_clusters != UINT_MAX) - p_fs->used_clusters += num_clusters; - - p_chain->size += num_clusters; - return num_clusters; - } - - hint_clu = new_clu + 1; - if (hint_clu >= p_fs->num_clusters) { - hint_clu = 2; - - if (p_chain->flags == 0x03) { - exfat_chain_cont_cluster(sb, p_chain->dir, - num_clusters); - p_chain->flags = 0x01; - } - } - } - - p_fs->clu_srch_ptr = hint_clu; - if (p_fs->used_clusters != UINT_MAX) - p_fs->used_clusters += num_clusters; - - p_chain->size += num_clusters; - return num_clusters; -} - -void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain, - s32 do_relse) -{ - s32 num_clusters = 0; - u32 clu; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - int i; - sector_t sector; - - if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) - return; - - if (p_chain->size <= 0) { - pr_err("[EXFAT] free_cluster : skip free-req clu:%u, because of zero-size truncation\n", - p_chain->dir); - return; - } - - __set_sb_dirty(sb); - clu = p_chain->dir; - - if (p_chain->flags == 0x03) { - do { - if (do_relse) { - sector = START_SECTOR(clu); - for (i = 0; i < p_fs->sectors_per_clu; i++) - exfat_buf_release(sb, sector + i); - } - - if (clr_alloc_bitmap(sb, clu - 2) != 0) - break; - clu++; - - num_clusters++; - } while (num_clusters < p_chain->size); - } else { - do { - if (p_fs->dev_ejected) - break; - - if (do_relse) { - sector = START_SECTOR(clu); - for (i = 0; i < p_fs->sectors_per_clu; i++) - exfat_buf_release(sb, sector + i); - } - - if (clr_alloc_bitmap(sb, clu - 2) != 0) - break; - - if (exfat_fat_read(sb, clu, &clu) == -1) - break; - num_clusters++; - } while ((clu != CLUSTER_32(0)) && (clu != CLUSTER_32(~0))); - } - - if (p_fs->used_clusters != UINT_MAX) - p_fs->used_clusters -= num_clusters; -} - -static u32 find_last_cluster(struct super_block *sb, struct chain_t *p_chain) -{ - u32 clu, next; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - clu = p_chain->dir; - - if (p_chain->flags == 0x03) { - clu += p_chain->size - 1; - } else { - while ((exfat_fat_read(sb, clu, &next) == 0) && - (next != CLUSTER_32(~0))) { - if (p_fs->dev_ejected) - break; - clu = next; - } - } - - return clu; -} - -s32 count_num_clusters(struct super_block *sb, struct chain_t *p_chain) -{ - int i, count = 0; - u32 clu; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) - return 0; - - clu = p_chain->dir; - - if (p_chain->flags == 0x03) { - count = p_chain->size; - } else { - for (i = 2; i < p_fs->num_clusters; i++) { - count++; - if (exfat_fat_read(sb, clu, &clu) != 0) - return 0; - if (clu == CLUSTER_32(~0)) - break; - } - } - - return count; -} - -s32 exfat_count_used_clusters(struct super_block *sb) -{ - int i, map_i, map_b, count = 0; - u8 k; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - map_i = 0; - map_b = 0; - - for (i = 2; i < p_fs->num_clusters; i += 8) { - k = *(((u8 *)p_fs->vol_amap[map_i]->b_data) + map_b); - count += used_bit[k]; - - if ((++map_b) >= p_bd->sector_size) { - map_i++; - map_b = 0; - } - } - - return count; -} - -void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len) -{ - if (len == 0) - return; - - while (len > 1) { - if (exfat_fat_write(sb, chain, chain + 1) < 0) - break; - chain++; - len--; - } - exfat_fat_write(sb, chain, CLUSTER_32(~0)); -} - -/* - * Allocation Bitmap Management Functions - */ - -s32 load_alloc_bitmap(struct super_block *sb) -{ - int i, j, ret; - u32 map_size; - u32 type; - sector_t sector; - struct chain_t clu; - struct bmap_dentry_t *ep; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - clu.dir = p_fs->root_dir; - clu.flags = 0x01; - - while (clu.dir != CLUSTER_32(~0)) { - if (p_fs->dev_ejected) - break; - - for (i = 0; i < p_fs->dentries_per_clu; i++) { - ep = (struct bmap_dentry_t *)get_entry_in_dir(sb, &clu, - i, NULL); - if (!ep) - return -ENOENT; - - type = exfat_get_entry_type((struct dentry_t *)ep); - - if (type == TYPE_UNUSED) - break; - if (type != TYPE_BITMAP) - continue; - - if (ep->flags == 0x0) { - p_fs->map_clu = GET32_A(ep->start_clu); - map_size = (u32)GET64_A(ep->size); - - p_fs->map_sectors = ((map_size - 1) >> p_bd->sector_size_bits) + 1; - - p_fs->vol_amap = kmalloc_array(p_fs->map_sectors, - sizeof(struct buffer_head *), - GFP_KERNEL); - if (!p_fs->vol_amap) - return -ENOMEM; - - sector = START_SECTOR(p_fs->map_clu); - - for (j = 0; j < p_fs->map_sectors; j++) { - p_fs->vol_amap[j] = NULL; - ret = sector_read(sb, sector + j, &p_fs->vol_amap[j], 1); - if (ret != 0) { - /* release all buffers and free vol_amap */ - i = 0; - while (i < j) - brelse(p_fs->vol_amap[i++]); - - kfree(p_fs->vol_amap); - p_fs->vol_amap = NULL; - return ret; - } - } - - p_fs->pbr_bh = NULL; - return 0; - } - } - - if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) - return -EIO; - } - - return -EFSCORRUPTED; -} - -void free_alloc_bitmap(struct super_block *sb) -{ - int i; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - brelse(p_fs->pbr_bh); - - for (i = 0; i < p_fs->map_sectors; i++) - __brelse(p_fs->vol_amap[i]); - - kfree(p_fs->vol_amap); - p_fs->vol_amap = NULL; -} - -void sync_alloc_bitmap(struct super_block *sb) -{ - int i; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if (!p_fs->vol_amap) - return; - - for (i = 0; i < p_fs->map_sectors; i++) - sync_dirty_buffer(p_fs->vol_amap[i]); -} - -/* - * Upcase table Management Functions - */ -static s32 __load_upcase_table(struct super_block *sb, sector_t sector, - u32 num_sectors, u32 utbl_checksum) -{ - int i, ret = -EINVAL; - u32 j; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - struct buffer_head *tmp_bh = NULL; - sector_t end_sector = num_sectors + sector; - - bool skip = false; - u32 index = 0; - u16 uni = 0; - u16 **upcase_table; - - u32 checksum = 0; - - upcase_table = kmalloc_array(UTBL_COL_COUNT, sizeof(u16 *), GFP_KERNEL); - p_fs->vol_utbl = upcase_table; - if (!upcase_table) - return -ENOMEM; - memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); - - while (sector < end_sector) { - ret = sector_read(sb, sector, &tmp_bh, 1); - if (ret != 0) { - pr_debug("sector read (0x%llX)fail\n", - (unsigned long long)sector); - goto error; - } - sector++; - - for (i = 0; i < p_bd->sector_size && index <= 0xFFFF; i += 2) { - uni = GET16(((u8 *)tmp_bh->b_data) + i); - - checksum = ((checksum & 1) ? 0x80000000 : 0) + - (checksum >> 1) + *(((u8 *)tmp_bh->b_data) + - i); - checksum = ((checksum & 1) ? 0x80000000 : 0) + - (checksum >> 1) + *(((u8 *)tmp_bh->b_data) + - (i + 1)); - - if (skip) { - pr_debug("skip from 0x%X ", index); - index += uni; - pr_debug("to 0x%X (amount of 0x%X)\n", - index, uni); - skip = false; - } else if (uni == index) { - index++; - } else if (uni == 0xFFFF) { - skip = true; - } else { /* uni != index , uni != 0xFFFF */ - u16 col_index = get_col_index(index); - - if (!upcase_table[col_index]) { - pr_debug("alloc = 0x%X\n", col_index); - upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT, - sizeof(u16), GFP_KERNEL); - if (!upcase_table[col_index]) { - ret = -ENOMEM; - goto error; - } - - for (j = 0; j < UTBL_ROW_COUNT; j++) - upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; - } - - upcase_table[col_index][get_row_index(index)] = uni; - index++; - } - } - } - if (index >= 0xFFFF && utbl_checksum == checksum) { - if (tmp_bh) - brelse(tmp_bh); - return 0; - } - ret = -EINVAL; -error: - if (tmp_bh) - brelse(tmp_bh); - free_upcase_table(sb); - return ret; -} - -static s32 __load_default_upcase_table(struct super_block *sb) -{ - int i, ret = -EINVAL; - u32 j; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - bool skip = false; - u32 index = 0; - u16 uni = 0; - u16 **upcase_table; - - upcase_table = kmalloc_array(UTBL_COL_COUNT, sizeof(u16 *), GFP_KERNEL); - p_fs->vol_utbl = upcase_table; - if (!upcase_table) - return -ENOMEM; - memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); - - for (i = 0; index <= 0xFFFF && i < NUM_UPCASE * 2; i += 2) { - uni = GET16(uni_upcase + i); - if (skip) { - pr_debug("skip from 0x%X ", index); - index += uni; - pr_debug("to 0x%X (amount of 0x%X)\n", index, uni); - skip = false; - } else if (uni == index) { - index++; - } else if (uni == 0xFFFF) { - skip = true; - } else { /* uni != index , uni != 0xFFFF */ - u16 col_index = get_col_index(index); - - if (!upcase_table[col_index]) { - pr_debug("alloc = 0x%X\n", col_index); - upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT, - sizeof(u16), - GFP_KERNEL); - if (!upcase_table[col_index]) { - ret = -ENOMEM; - goto error; - } - - for (j = 0; j < UTBL_ROW_COUNT; j++) - upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; - } - - upcase_table[col_index][get_row_index(index)] = uni; - index++; - } - } - - if (index >= 0xFFFF) - return 0; - -error: - /* FATAL error: default upcase table has error */ - free_upcase_table(sb); - return ret; -} - -s32 load_upcase_table(struct super_block *sb) -{ - int i; - u32 tbl_clu, tbl_size; - sector_t sector; - u32 type, num_sectors; - struct chain_t clu; - struct case_dentry_t *ep; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - clu.dir = p_fs->root_dir; - clu.flags = 0x01; - - if (p_fs->dev_ejected) - return -EIO; - - while (clu.dir != CLUSTER_32(~0)) { - for (i = 0; i < p_fs->dentries_per_clu; i++) { - ep = (struct case_dentry_t *)get_entry_in_dir(sb, &clu, - i, NULL); - if (!ep) - return -ENOENT; - - type = exfat_get_entry_type((struct dentry_t *)ep); - - if (type == TYPE_UNUSED) - break; - if (type != TYPE_UPCASE) - continue; - - tbl_clu = GET32_A(ep->start_clu); - tbl_size = (u32)GET64_A(ep->size); - - sector = START_SECTOR(tbl_clu); - num_sectors = ((tbl_size - 1) >> p_bd->sector_size_bits) + 1; - if (__load_upcase_table(sb, sector, num_sectors, - GET32_A(ep->checksum)) != 0) - break; - return 0; - } - if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) - return -EIO; - } - /* load default upcase table */ - return __load_default_upcase_table(sb); -} - -void free_upcase_table(struct super_block *sb) -{ - u32 i; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - u16 **upcase_table; - - upcase_table = p_fs->vol_utbl; - for (i = 0; i < UTBL_COL_COUNT; i++) - kfree(upcase_table[i]); - - kfree(p_fs->vol_utbl); - p_fs->vol_utbl = NULL; -} - -/* - * Directory Entry Management Functions - */ - -u32 exfat_get_entry_type(struct dentry_t *p_entry) -{ - struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; - - if (ep->type == 0x0) { - return TYPE_UNUSED; - } else if (ep->type < 0x80) { - return TYPE_DELETED; - } else if (ep->type == 0x80) { - return TYPE_INVALID; - } else if (ep->type < 0xA0) { - if (ep->type == 0x81) { - return TYPE_BITMAP; - } else if (ep->type == 0x82) { - return TYPE_UPCASE; - } else if (ep->type == 0x83) { - return TYPE_VOLUME; - } else if (ep->type == 0x85) { - if (GET16_A(ep->attr) & ATTR_SUBDIR) - return TYPE_DIR; - else - return TYPE_FILE; - } - return TYPE_CRITICAL_PRI; - } else if (ep->type < 0xC0) { - if (ep->type == 0xA0) - return TYPE_GUID; - else if (ep->type == 0xA1) - return TYPE_PADDING; - else if (ep->type == 0xA2) - return TYPE_ACLTAB; - return TYPE_BENIGN_PRI; - } else if (ep->type < 0xE0) { - if (ep->type == 0xC0) - return TYPE_STREAM; - else if (ep->type == 0xC1) - return TYPE_EXTEND; - else if (ep->type == 0xC2) - return TYPE_ACL; - return TYPE_CRITICAL_SEC; - } - - return TYPE_BENIGN_SEC; -} - -static void exfat_set_entry_type(struct dentry_t *p_entry, u32 type) -{ - struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; - - if (type == TYPE_UNUSED) { - ep->type = 0x0; - } else if (type == TYPE_DELETED) { - ep->type &= ~0x80; - } else if (type == TYPE_STREAM) { - ep->type = 0xC0; - } else if (type == TYPE_EXTEND) { - ep->type = 0xC1; - } else if (type == TYPE_BITMAP) { - ep->type = 0x81; - } else if (type == TYPE_UPCASE) { - ep->type = 0x82; - } else if (type == TYPE_VOLUME) { - ep->type = 0x83; - } else if (type == TYPE_DIR) { - ep->type = 0x85; - SET16_A(ep->attr, ATTR_SUBDIR); - } else if (type == TYPE_FILE) { - ep->type = 0x85; - SET16_A(ep->attr, ATTR_ARCHIVE); - } else if (type == TYPE_SYMLINK) { - ep->type = 0x85; - SET16_A(ep->attr, ATTR_ARCHIVE | ATTR_SYMLINK); - } -} - -u32 exfat_get_entry_attr(struct dentry_t *p_entry) -{ - struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; - - return (u32)GET16_A(ep->attr); -} - -void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr) -{ - struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; - - SET16_A(ep->attr, (u16)attr); -} - -u8 exfat_get_entry_flag(struct dentry_t *p_entry) -{ - struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; - - return ep->flags; -} - -void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flags) -{ - struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; - - ep->flags = flags; -} - -u32 exfat_get_entry_clu0(struct dentry_t *p_entry) -{ - struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; - - return GET32_A(ep->start_clu); -} - -void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu) -{ - struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; - - SET32_A(ep->start_clu, start_clu); -} - -u64 exfat_get_entry_size(struct dentry_t *p_entry) -{ - struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; - - return GET64_A(ep->valid_size); -} - -void exfat_set_entry_size(struct dentry_t *p_entry, u64 size) -{ - struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry; - - SET64_A(ep->valid_size, size); - SET64_A(ep->size, size); -} - -void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, - u8 mode) -{ - u16 t = 0x00, d = 0x21; - struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; - - switch (mode) { - case TM_CREATE: - t = GET16_A(ep->create_time); - d = GET16_A(ep->create_date); - break; - case TM_MODIFY: - t = GET16_A(ep->modify_time); - d = GET16_A(ep->modify_date); - break; - case TM_ACCESS: - t = GET16_A(ep->access_time); - d = GET16_A(ep->access_date); - break; - } - - tp->sec = (t & 0x001F) << 1; - tp->min = (t >> 5) & 0x003F; - tp->hour = (t >> 11); - tp->day = (d & 0x001F); - tp->mon = (d >> 5) & 0x000F; - tp->year = (d >> 9); -} - -void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, - u8 mode) -{ - u16 t, d; - struct file_dentry_t *ep = (struct file_dentry_t *)p_entry; - - t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1); - d = (tp->year << 9) | (tp->mon << 5) | tp->day; - - switch (mode) { - case TM_CREATE: - SET16_A(ep->create_time, t); - SET16_A(ep->create_date, d); - break; - case TM_MODIFY: - SET16_A(ep->modify_time, t); - SET16_A(ep->modify_date, d); - break; - case TM_ACCESS: - SET16_A(ep->access_time, t); - SET16_A(ep->access_date, d); - break; - } -} - -static void init_file_entry(struct file_dentry_t *ep, u32 type) -{ - struct timestamp_t tm, *tp; - - exfat_set_entry_type((struct dentry_t *)ep, type); - - tp = tm_current(&tm); - exfat_set_entry_time((struct dentry_t *)ep, tp, TM_CREATE); - exfat_set_entry_time((struct dentry_t *)ep, tp, TM_MODIFY); - exfat_set_entry_time((struct dentry_t *)ep, tp, TM_ACCESS); - ep->create_time_ms = 0; - ep->modify_time_ms = 0; - ep->access_time_ms = 0; -} - -static void init_strm_entry(struct strm_dentry_t *ep, u8 flags, u32 start_clu, u64 size) -{ - exfat_set_entry_type((struct dentry_t *)ep, TYPE_STREAM); - ep->flags = flags; - SET32_A(ep->start_clu, start_clu); - SET64_A(ep->valid_size, size); - SET64_A(ep->size, size); -} - -static void init_name_entry(struct name_dentry_t *ep, u16 *uniname) -{ - int i; - - exfat_set_entry_type((struct dentry_t *)ep, TYPE_EXTEND); - ep->flags = 0x0; - - for (i = 0; i < 30; i++, i++) { - SET16_A(ep->unicode_0_14 + i, *uniname); - if (*uniname == 0x0) - break; - uniname++; - } -} - -static s32 exfat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir, - s32 entry, u32 type, u32 start_clu, u64 size) -{ - sector_t sector; - u8 flags; - struct file_dentry_t *file_ep; - struct strm_dentry_t *strm_ep; - - flags = (type == TYPE_FILE) ? 0x01 : 0x03; - - /* we cannot use get_entry_set_in_dir here because file ep is not initialized yet */ - file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, - §or); - if (!file_ep) - return -ENOENT; - - strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry + 1, - §or); - if (!strm_ep) - return -ENOENT; - - init_file_entry(file_ep, type); - exfat_buf_modify(sb, sector); - - init_strm_entry(strm_ep, flags, start_clu, size); - exfat_buf_modify(sb, sector); - - return 0; -} - -static s32 exfat_init_ext_entry(struct super_block *sb, struct chain_t *p_dir, - s32 entry, s32 num_entries, - struct uni_name_t *p_uniname, - struct dos_name_t *p_dosname) -{ - int i; - sector_t sector; - u16 *uniname = p_uniname->name; - struct file_dentry_t *file_ep; - struct strm_dentry_t *strm_ep; - struct name_dentry_t *name_ep; - - file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, - §or); - if (!file_ep) - return -ENOENT; - - file_ep->num_ext = (u8)(num_entries - 1); - exfat_buf_modify(sb, sector); - - strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry + 1, - §or); - if (!strm_ep) - return -ENOENT; - - strm_ep->name_len = p_uniname->name_len; - SET16_A(strm_ep->name_hash, p_uniname->name_hash); - exfat_buf_modify(sb, sector); - - for (i = 2; i < num_entries; i++) { - name_ep = (struct name_dentry_t *)get_entry_in_dir(sb, p_dir, - entry + i, - §or); - if (!name_ep) - return -ENOENT; - - init_name_entry(name_ep, uniname); - exfat_buf_modify(sb, sector); - uniname += 15; - } - - update_dir_checksum(sb, p_dir, entry); - - return 0; -} - -void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, - s32 entry, s32 order, s32 num_entries) -{ - int i; - sector_t sector; - struct dentry_t *ep; - - for (i = order; i < num_entries; i++) { - ep = get_entry_in_dir(sb, p_dir, entry + i, §or); - if (!ep) - return; - - exfat_set_entry_type(ep, TYPE_DELETED); - exfat_buf_modify(sb, sector); - } -} - -void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir, - s32 entry) -{ - int i, num_entries; - sector_t sector; - u16 chksum; - struct file_dentry_t *file_ep; - struct dentry_t *ep; - - file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry, - §or); - if (!file_ep) - return; - - exfat_buf_lock(sb, sector); - - num_entries = (s32)file_ep->num_ext + 1; - chksum = calc_checksum_2byte((void *)file_ep, DENTRY_SIZE, 0, - CS_DIR_ENTRY); - - for (i = 1; i < num_entries; i++) { - ep = get_entry_in_dir(sb, p_dir, entry + i, NULL); - if (!ep) { - exfat_buf_unlock(sb, sector); - return; - } - - chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum, - CS_DEFAULT); - } - - SET16_A(file_ep->checksum, chksum); - exfat_buf_modify(sb, sector); - exfat_buf_unlock(sb, sector); -} - -static s32 __write_partial_entries_in_entry_set(struct super_block *sb, - struct entry_set_cache_t *es, - sector_t sec, s32 off, u32 count) -{ - s32 num_entries, buf_off = (off - es->offset); - u32 remaining_byte_in_sector, copy_entries; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - u32 clu; - u8 *buf, *esbuf = (u8 *)&es->__buf; - - pr_debug("%s entered es %p sec %llu off %d count %d\n", - __func__, es, (unsigned long long)sec, off, count); - num_entries = count; - - while (num_entries) { - /* white per sector base */ - remaining_byte_in_sector = (1 << p_bd->sector_size_bits) - off; - copy_entries = min_t(s32, - remaining_byte_in_sector >> DENTRY_SIZE_BITS, - num_entries); - buf = exfat_buf_getblk(sb, sec); - if (!buf) - goto err_out; - pr_debug("es->buf %p buf_off %u\n", esbuf, buf_off); - pr_debug("copying %d entries from %p to sector %llu\n", - copy_entries, (esbuf + buf_off), - (unsigned long long)sec); - memcpy(buf + off, esbuf + buf_off, - copy_entries << DENTRY_SIZE_BITS); - exfat_buf_modify(sb, sec); - num_entries -= copy_entries; - - if (num_entries) { - /* get next sector */ - if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { - clu = GET_CLUSTER_FROM_SECTOR(sec); - if (es->alloc_flag == 0x03) { - clu++; - } else { - if (exfat_fat_read(sb, clu, &clu) == -1) - goto err_out; - } - sec = START_SECTOR(clu); - } else { - sec++; - } - off = 0; - buf_off += copy_entries << DENTRY_SIZE_BITS; - } - } - - pr_debug("%s exited successfully\n", __func__); - return 0; -err_out: - pr_debug("%s failed\n", __func__); - return -EINVAL; -} - -/* write back all entries in entry set */ -static s32 write_whole_entry_set(struct super_block *sb, struct entry_set_cache_t *es) -{ - return __write_partial_entries_in_entry_set(sb, es, es->sector, - es->offset, - es->num_entries); -} - -void update_dir_checksum_with_entry_set(struct super_block *sb, - struct entry_set_cache_t *es) -{ - struct dentry_t *ep; - u16 chksum = 0; - s32 chksum_type = CS_DIR_ENTRY, i; - - ep = (struct dentry_t *)&es->__buf; - for (i = 0; i < es->num_entries; i++) { - pr_debug("%s ep %p\n", __func__, ep); - chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum, - chksum_type); - ep++; - chksum_type = CS_DEFAULT; - } - - ep = (struct dentry_t *)&es->__buf; - SET16_A(((struct file_dentry_t *)ep)->checksum, chksum); - write_whole_entry_set(sb, es); -} - -static s32 _walk_fat_chain(struct super_block *sb, struct chain_t *p_dir, - s32 byte_offset, u32 *clu) -{ - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - s32 clu_offset; - u32 cur_clu; - - clu_offset = byte_offset >> p_fs->cluster_size_bits; - cur_clu = p_dir->dir; - - if (p_dir->flags == 0x03) { - cur_clu += clu_offset; - } else { - while (clu_offset > 0) { - if (exfat_fat_read(sb, cur_clu, &cur_clu) == -1) - return -EIO; - clu_offset--; - } - } - - if (clu) - *clu = cur_clu; - return 0; -} - -static s32 find_location(struct super_block *sb, struct chain_t *p_dir, s32 entry, - sector_t *sector, s32 *offset) -{ - s32 off, ret; - u32 clu = 0; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - off = entry << DENTRY_SIZE_BITS; - - if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */ - *offset = off & p_bd->sector_size_mask; - *sector = off >> p_bd->sector_size_bits; - *sector += p_fs->root_start_sector; - } else { - ret = _walk_fat_chain(sb, p_dir, off, &clu); - if (ret != 0) - return ret; - - /* byte offset in cluster */ - off &= p_fs->cluster_size - 1; - - /* byte offset in sector */ - *offset = off & p_bd->sector_size_mask; - - /* sector offset in cluster */ - *sector = off >> p_bd->sector_size_bits; - *sector += START_SECTOR(clu); - } - return 0; -} - -struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir, - s32 entry, sector_t *sector) -{ - s32 off; - sector_t sec; - u8 *buf; - - if (find_location(sb, p_dir, entry, &sec, &off) != 0) - return NULL; - - buf = exfat_buf_getblk(sb, sec); - - if (!buf) - return NULL; - - if (sector) - *sector = sec; - return (struct dentry_t *)(buf + off); -} - -/* returns a set of dentries for a file or dir. - * Note that this is a copy (dump) of dentries so that user should call write_entry_set() - * to apply changes made in this entry set to the real device. - * in: - * sb+p_dir+entry: indicates a file/dir - * type: specifies how many dentries should be included. - * out: - * file_ep: will point the first dentry(= file dentry) on success - * return: - * pointer of entry set on success, - * NULL on failure. - */ - -#define ES_MODE_STARTED 0 -#define ES_MODE_GET_FILE_ENTRY 1 -#define ES_MODE_GET_STRM_ENTRY 2 -#define ES_MODE_GET_NAME_ENTRY 3 -#define ES_MODE_GET_CRITICAL_SEC_ENTRY 4 -struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb, - struct chain_t *p_dir, s32 entry, - u32 type, - struct dentry_t **file_ep) -{ - s32 off, ret, byte_offset; - u32 clu = 0; - sector_t sec; - u32 entry_type; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - struct entry_set_cache_t *es = NULL; - struct dentry_t *ep, *pos; - u8 *buf; - u8 num_entries; - s32 mode = ES_MODE_STARTED; - size_t bufsize; - - pr_debug("%s entered p_dir dir %u flags %x size %d\n", - __func__, p_dir->dir, p_dir->flags, p_dir->size); - - byte_offset = entry << DENTRY_SIZE_BITS; - ret = _walk_fat_chain(sb, p_dir, byte_offset, &clu); - if (ret != 0) - return NULL; - - /* byte offset in cluster */ - byte_offset &= p_fs->cluster_size - 1; - - /* byte offset in sector */ - off = byte_offset & p_bd->sector_size_mask; - - /* sector offset in cluster */ - sec = byte_offset >> p_bd->sector_size_bits; - sec += START_SECTOR(clu); - - buf = exfat_buf_getblk(sb, sec); - if (!buf) - goto err_out; - - ep = (struct dentry_t *)(buf + off); - entry_type = exfat_get_entry_type(ep); - - if ((entry_type != TYPE_FILE) && (entry_type != TYPE_DIR)) - goto err_out; - - if (type == ES_ALL_ENTRIES) - num_entries = ((struct file_dentry_t *)ep)->num_ext + 1; - else - num_entries = type; - - bufsize = offsetof(struct entry_set_cache_t, __buf) + (num_entries) * - sizeof(struct dentry_t); - pr_debug("%s: trying to kmalloc %zx bytes for %d entries\n", __func__, - bufsize, num_entries); - es = kmalloc(bufsize, GFP_KERNEL); - if (!es) - goto err_out; - - es->num_entries = num_entries; - es->sector = sec; - es->offset = off; - es->alloc_flag = p_dir->flags; - - pos = (struct dentry_t *)&es->__buf; - - while (num_entries) { - /* - * instead of copying whole sector, we will check every entry. - * this will provide minimum stablity and consistency. - */ - entry_type = exfat_get_entry_type(ep); - - if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) - goto err_out; - - switch (mode) { - case ES_MODE_STARTED: - if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) - mode = ES_MODE_GET_FILE_ENTRY; - else - goto err_out; - break; - case ES_MODE_GET_FILE_ENTRY: - if (entry_type == TYPE_STREAM) - mode = ES_MODE_GET_STRM_ENTRY; - else - goto err_out; - break; - case ES_MODE_GET_STRM_ENTRY: - if (entry_type == TYPE_EXTEND) - mode = ES_MODE_GET_NAME_ENTRY; - else - goto err_out; - break; - case ES_MODE_GET_NAME_ENTRY: - if (entry_type == TYPE_EXTEND) - break; - else if (entry_type == TYPE_STREAM) - goto err_out; - else if (entry_type & TYPE_CRITICAL_SEC) - mode = ES_MODE_GET_CRITICAL_SEC_ENTRY; - else - goto err_out; - break; - case ES_MODE_GET_CRITICAL_SEC_ENTRY: - if ((entry_type == TYPE_EXTEND) || - (entry_type == TYPE_STREAM)) - goto err_out; - else if ((entry_type & TYPE_CRITICAL_SEC) != - TYPE_CRITICAL_SEC) - goto err_out; - break; - } - - memcpy(pos, ep, sizeof(struct dentry_t)); - - if (--num_entries == 0) - break; - - if (((off + DENTRY_SIZE) & p_bd->sector_size_mask) < - (off & p_bd->sector_size_mask)) { - /* get the next sector */ - if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { - if (es->alloc_flag == 0x03) { - clu++; - } else { - if (exfat_fat_read(sb, clu, &clu) == -1) - goto err_out; - } - sec = START_SECTOR(clu); - } else { - sec++; - } - buf = exfat_buf_getblk(sb, sec); - if (!buf) - goto err_out; - off = 0; - ep = (struct dentry_t *)(buf); - } else { - ep++; - off += DENTRY_SIZE; - } - pos++; - } - - if (file_ep) - *file_ep = (struct dentry_t *)&es->__buf; - - pr_debug("%s exiting es %p sec %llu offset %d flags %d, num_entries %u buf ptr %p\n", - __func__, es, (unsigned long long)es->sector, es->offset, - es->alloc_flag, es->num_entries, &es->__buf); - return es; -err_out: - pr_debug("%s exited NULL (es %p)\n", __func__, es); - kfree(es); - return NULL; -} - -void release_entry_set(struct entry_set_cache_t *es) -{ - pr_debug("%s es=%p\n", __func__, es); - kfree(es); -} - -/* search EMPTY CONTINUOUS "num_entries" entries */ -static s32 search_deleted_or_unused_entry(struct super_block *sb, - struct chain_t *p_dir, - s32 num_entries) -{ - int i, dentry, num_empty = 0; - s32 dentries_per_clu; - u32 type; - struct chain_t clu; - struct dentry_t *ep; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ - dentries_per_clu = p_fs->dentries_in_root; - else - dentries_per_clu = p_fs->dentries_per_clu; - - if (p_fs->hint_uentry.dir == p_dir->dir) { - if (p_fs->hint_uentry.entry == -1) - return -1; - - clu.dir = p_fs->hint_uentry.clu.dir; - clu.size = p_fs->hint_uentry.clu.size; - clu.flags = p_fs->hint_uentry.clu.flags; - - dentry = p_fs->hint_uentry.entry; - } else { - p_fs->hint_uentry.entry = -1; - - clu.dir = p_dir->dir; - clu.size = p_dir->size; - clu.flags = p_dir->flags; - - dentry = 0; - } - - while (clu.dir != CLUSTER_32(~0)) { - if (p_fs->dev_ejected) - break; - - if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ - i = dentry % dentries_per_clu; - else - i = dentry & (dentries_per_clu - 1); - - for (; i < dentries_per_clu; i++, dentry++) { - ep = get_entry_in_dir(sb, &clu, i, NULL); - if (!ep) - return -1; - - type = exfat_get_entry_type(ep); - - if (type == TYPE_UNUSED) { - num_empty++; - if (p_fs->hint_uentry.entry == -1) { - p_fs->hint_uentry.dir = p_dir->dir; - p_fs->hint_uentry.entry = dentry; - - p_fs->hint_uentry.clu.dir = clu.dir; - p_fs->hint_uentry.clu.size = clu.size; - p_fs->hint_uentry.clu.flags = clu.flags; - } - } else if (type == TYPE_DELETED) { - num_empty++; - } else { - num_empty = 0; - } - - if (num_empty >= num_entries) { - p_fs->hint_uentry.dir = CLUSTER_32(~0); - p_fs->hint_uentry.entry = -1; - - if (p_fs->vol_type == EXFAT) - return dentry - (num_entries - 1); - else - return dentry; - } - } - - if (p_dir->dir == CLUSTER_32(0)) - break; /* FAT16 root_dir */ - - if (clu.flags == 0x03) { - if ((--clu.size) > 0) - clu.dir++; - else - clu.dir = CLUSTER_32(~0); - } else { - if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) - return -1; - } - } - - return -1; -} - -static s32 find_empty_entry(struct inode *inode, struct chain_t *p_dir, s32 num_entries) -{ - s32 ret, dentry; - u32 last_clu; - sector_t sector; - u64 size = 0; - struct chain_t clu; - struct dentry_t *ep = NULL; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct file_id_t *fid = &(EXFAT_I(inode)->fid); - - if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ - return search_deleted_or_unused_entry(sb, p_dir, num_entries); - - while ((dentry = search_deleted_or_unused_entry(sb, p_dir, num_entries)) < 0) { - if (p_fs->dev_ejected) - break; - - if (p_dir->dir != p_fs->root_dir) - size = i_size_read(inode); - - last_clu = find_last_cluster(sb, p_dir); - clu.dir = last_clu + 1; - clu.size = 0; - clu.flags = p_dir->flags; - - /* (1) allocate a cluster */ - ret = exfat_alloc_cluster(sb, 1, &clu); - if (ret < 1) - return -EIO; - - if (clear_cluster(sb, clu.dir) != 0) - return -EIO; - - /* (2) append to the FAT chain */ - if (clu.flags != p_dir->flags) { - exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size); - p_dir->flags = 0x01; - p_fs->hint_uentry.clu.flags = 0x01; - } - if (clu.flags == 0x01) - if (exfat_fat_write(sb, last_clu, clu.dir) < 0) - return -EIO; - - if (p_fs->hint_uentry.entry == -1) { - p_fs->hint_uentry.dir = p_dir->dir; - p_fs->hint_uentry.entry = p_dir->size << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); - - p_fs->hint_uentry.clu.dir = clu.dir; - p_fs->hint_uentry.clu.size = 0; - p_fs->hint_uentry.clu.flags = clu.flags; - } - p_fs->hint_uentry.clu.size++; - p_dir->size++; - - /* (3) update the directory entry */ - if (p_dir->dir != p_fs->root_dir) { - size += p_fs->cluster_size; - - ep = get_entry_in_dir(sb, &fid->dir, - fid->entry + 1, §or); - if (!ep) - return -ENOENT; - exfat_set_entry_size(ep, size); - exfat_set_entry_flag(ep, p_dir->flags); - exfat_buf_modify(sb, sector); - - update_dir_checksum(sb, &fid->dir, - fid->entry); - } - - i_size_write(inode, i_size_read(inode) + p_fs->cluster_size); - EXFAT_I(inode)->mmu_private += p_fs->cluster_size; - EXFAT_I(inode)->fid.size += p_fs->cluster_size; - EXFAT_I(inode)->fid.flags = p_dir->flags; - inode->i_blocks += 1 << (p_fs->cluster_size_bits - 9); - } - - return dentry; -} - -static s32 extract_uni_name_from_name_entry(struct name_dentry_t *ep, u16 *uniname, - s32 order) -{ - int i, len = 0; - - for (i = 0; i < 30; i += 2) { - *uniname = GET16_A(ep->unicode_0_14 + i); - if (*uniname == 0x0) - return len; - uniname++; - len++; - } - - *uniname = 0x0; - return len; -} - -/* return values of exfat_find_dir_entry() - * >= 0 : return dir entiry position with the name in dir - * -1 : (root dir, ".") it is the root dir itself - * -2 : entry with the name does not exist - */ -s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir, - struct uni_name_t *p_uniname, s32 num_entries, - struct dos_name_t *p_dosname, u32 type) -{ - int i = 0, dentry = 0, num_ext_entries = 0, len, step; - s32 order = 0; - bool is_feasible_entry = false; - s32 dentries_per_clu, num_empty = 0; - u32 entry_type; - u16 entry_uniname[16], *uniname = NULL, unichar; - struct chain_t clu; - struct dentry_t *ep; - struct file_dentry_t *file_ep; - struct strm_dentry_t *strm_ep; - struct name_dentry_t *name_ep; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if (p_dir->dir == p_fs->root_dir) { - if ((!nls_uniname_cmp(sb, p_uniname->name, - (u16 *)UNI_CUR_DIR_NAME)) || - (!nls_uniname_cmp(sb, p_uniname->name, - (u16 *)UNI_PAR_DIR_NAME))) - return -1; // special case, root directory itself - } - - if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ - dentries_per_clu = p_fs->dentries_in_root; - else - dentries_per_clu = p_fs->dentries_per_clu; - - clu.dir = p_dir->dir; - clu.size = p_dir->size; - clu.flags = p_dir->flags; - - p_fs->hint_uentry.dir = p_dir->dir; - p_fs->hint_uentry.entry = -1; - - while (clu.dir != CLUSTER_32(~0)) { - if (p_fs->dev_ejected) - break; - - while (i < dentries_per_clu) { - ep = get_entry_in_dir(sb, &clu, i, NULL); - if (!ep) - return -2; - - entry_type = exfat_get_entry_type(ep); - step = 1; - - if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) { - is_feasible_entry = false; - - if (p_fs->hint_uentry.entry == -1) { - num_empty++; - - if (num_empty == 1) { - p_fs->hint_uentry.clu.dir = clu.dir; - p_fs->hint_uentry.clu.size = clu.size; - p_fs->hint_uentry.clu.flags = clu.flags; - } - if ((num_empty >= num_entries) || (entry_type == TYPE_UNUSED)) - p_fs->hint_uentry.entry = dentry - (num_empty - 1); - } - - if (entry_type == TYPE_UNUSED) - return -2; - } else { - num_empty = 0; - - if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) { - file_ep = (struct file_dentry_t *)ep; - if ((type == TYPE_ALL) || (type == entry_type)) { - num_ext_entries = file_ep->num_ext; - is_feasible_entry = true; - } else { - is_feasible_entry = false; - step = file_ep->num_ext + 1; - } - } else if (entry_type == TYPE_STREAM) { - if (is_feasible_entry) { - strm_ep = (struct strm_dentry_t *)ep; - if (p_uniname->name_hash == GET16_A(strm_ep->name_hash) && - p_uniname->name_len == strm_ep->name_len) { - order = 1; - } else { - is_feasible_entry = false; - step = num_ext_entries; - } - } - } else if (entry_type == TYPE_EXTEND) { - if (is_feasible_entry) { - name_ep = (struct name_dentry_t *)ep; - - if ((++order) == 2) - uniname = p_uniname->name; - else - uniname += 15; - - len = extract_uni_name_from_name_entry(name_ep, - entry_uniname, order); - - unichar = *(uniname + len); - *(uniname + len) = 0x0; - - if (nls_uniname_cmp(sb, uniname, entry_uniname)) { - is_feasible_entry = false; - step = num_ext_entries - order + 1; - } else if (order == num_ext_entries) { - p_fs->hint_uentry.dir = CLUSTER_32(~0); - p_fs->hint_uentry.entry = -1; - return dentry - (num_ext_entries); - } - - *(uniname + len) = unichar; - } - } else { - is_feasible_entry = false; - } - } - - i += step; - dentry += step; - } - - i -= dentries_per_clu; - - if (p_dir->dir == CLUSTER_32(0)) - break; /* FAT16 root_dir */ - - if (clu.flags == 0x03) { - if ((--clu.size) > 0) - clu.dir++; - else - clu.dir = CLUSTER_32(~0); - } else { - if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) - return -2; - } - } - - return -2; -} - -s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, - s32 entry, struct dentry_t *p_entry) -{ - int i, count = 0; - u32 type; - struct file_dentry_t *file_ep = (struct file_dentry_t *)p_entry; - struct dentry_t *ext_ep; - - for (i = 0, entry++; i < file_ep->num_ext; i++, entry++) { - ext_ep = get_entry_in_dir(sb, p_dir, entry, NULL); - if (!ext_ep) - return -1; - - type = exfat_get_entry_type(ext_ep); - if ((type == TYPE_EXTEND) || (type == TYPE_STREAM)) - count++; - else - return count; - } - - return count; -} - -s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir, - u32 type) -{ - int i, count = 0; - s32 dentries_per_clu; - u32 entry_type; - struct chain_t clu; - struct dentry_t *ep; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ - dentries_per_clu = p_fs->dentries_in_root; - else - dentries_per_clu = p_fs->dentries_per_clu; - - clu.dir = p_dir->dir; - clu.size = p_dir->size; - clu.flags = p_dir->flags; - - while (clu.dir != CLUSTER_32(~0)) { - if (p_fs->dev_ejected) - break; - - for (i = 0; i < dentries_per_clu; i++) { - ep = get_entry_in_dir(sb, &clu, i, NULL); - if (!ep) - return -ENOENT; - - entry_type = exfat_get_entry_type(ep); - - if (entry_type == TYPE_UNUSED) - return count; - if (!(type & TYPE_CRITICAL_PRI) && - !(type & TYPE_BENIGN_PRI)) - continue; - - if ((type == TYPE_ALL) || (type == entry_type)) - count++; - } - - if (p_dir->dir == CLUSTER_32(0)) - break; /* FAT16 root_dir */ - - if (clu.flags == 0x03) { - if ((--clu.size) > 0) - clu.dir++; - else - clu.dir = CLUSTER_32(~0); - } else { - if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) - return -EIO; - } - } - - return count; -} - -bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir) -{ - int i, count = 0; - s32 dentries_per_clu; - u32 type; - struct chain_t clu; - struct dentry_t *ep; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ - dentries_per_clu = p_fs->dentries_in_root; - else - dentries_per_clu = p_fs->dentries_per_clu; - - clu.dir = p_dir->dir; - clu.size = p_dir->size; - clu.flags = p_dir->flags; - - while (clu.dir != CLUSTER_32(~0)) { - if (p_fs->dev_ejected) - break; - - for (i = 0; i < dentries_per_clu; i++) { - ep = get_entry_in_dir(sb, &clu, i, NULL); - if (!ep) - break; - - type = exfat_get_entry_type(ep); - - if (type == TYPE_UNUSED) - return true; - if ((type != TYPE_FILE) && (type != TYPE_DIR)) - continue; - - if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ - return false; - - if (p_fs->vol_type == EXFAT) - return false; - if ((p_dir->dir == p_fs->root_dir) || ((++count) > 2)) - return false; - } - - if (p_dir->dir == CLUSTER_32(0)) - break; /* FAT16 root_dir */ - - if (clu.flags == 0x03) { - if ((--clu.size) > 0) - clu.dir++; - else - clu.dir = CLUSTER_32(~0); - } - if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0) - break; - } - - return true; -} - -/* - * Name Conversion Functions - */ - -/* input : dir, uni_name - * output : num_of_entry, dos_name(format : aaaaaa~1.bbb) - */ -s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir, - struct uni_name_t *p_uniname, s32 *entries, - struct dos_name_t *p_dosname) -{ - s32 num_entries; - - num_entries = exfat_calc_num_entries(p_uniname); - if (num_entries == 0) - return -EINVAL; - - *entries = num_entries; - - return 0; -} - -void exfat_get_uni_name_from_ext_entry(struct super_block *sb, - struct chain_t *p_dir, s32 entry, - u16 *uniname) -{ - int i; - struct dentry_t *ep; - struct entry_set_cache_t *es; - - es = get_entry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); - if (!es || es->num_entries < 3) { - if (es) - release_entry_set(es); - return; - } - - ep += 2; - - /* - * First entry : file entry - * Second entry : stream-extension entry - * Third entry : first file-name entry - * So, the index of first file-name dentry should start from 2. - */ - for (i = 2; i < es->num_entries; i++, ep++) { - if (exfat_get_entry_type(ep) == TYPE_EXTEND) - extract_uni_name_from_name_entry((struct name_dentry_t *) - ep, uniname, i); - else - goto out; - uniname += 15; - } - -out: - release_entry_set(es); -} - -s32 exfat_calc_num_entries(struct uni_name_t *p_uniname) -{ - s32 len; - - len = p_uniname->name_len; - if (len == 0) - return 0; - - /* 1 file entry + 1 stream entry + name entries */ - return (len - 1) / 15 + 3; -} - -u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type) -{ - int i; - u8 *c = (u8 *)data; - - switch (type) { - case CS_DIR_ENTRY: - for (i = 0; i < len; i++, c++) { - if ((i == 2) || (i == 3)) - continue; - chksum = (((chksum & 1) << 15) | - ((chksum & 0xFFFE) >> 1)) + (u16)*c; - } - break; - default - : - for (i = 0; i < len; i++, c++) - chksum = (((chksum & 1) << 15) | - ((chksum & 0xFFFE) >> 1)) + (u16)*c; - } - - return chksum; -} - -/* - * Name Resolution Functions - */ - -/* return values of resolve_path() - * > 0 : return the length of the path - * < 0 : return error - */ -s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir, - struct uni_name_t *p_uniname) -{ - bool lossy = false; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct file_id_t *fid = &(EXFAT_I(inode)->fid); - - if (strscpy(name_buf, path, sizeof(name_buf)) < 0) - return -EINVAL; - - nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy); - if (lossy) - return -EINVAL; - - fid->size = i_size_read(inode); - - p_dir->dir = fid->start_clu; - p_dir->size = (s32)(fid->size >> p_fs->cluster_size_bits); - p_dir->flags = fid->flags; - - return 0; -} - -s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr) -{ - struct bpbex_t *p_bpb = (struct bpbex_t *)p_pbr->bpb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - if (p_bpb->num_fats == 0) - return -EFSCORRUPTED; - - p_fs->sectors_per_clu = 1 << p_bpb->sectors_per_clu_bits; - p_fs->sectors_per_clu_bits = p_bpb->sectors_per_clu_bits; - p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + - p_bd->sector_size_bits; - p_fs->cluster_size = 1 << p_fs->cluster_size_bits; - - p_fs->num_FAT_sectors = GET32(p_bpb->fat_length); - - p_fs->FAT1_start_sector = p_fs->PBR_sector + GET32(p_bpb->fat_offset); - if (p_bpb->num_fats == 1) - p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; - else - p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + - p_fs->num_FAT_sectors; - - p_fs->root_start_sector = p_fs->PBR_sector + GET32(p_bpb->clu_offset); - p_fs->data_start_sector = p_fs->root_start_sector; - - p_fs->num_sectors = GET64(p_bpb->vol_length); - p_fs->num_clusters = GET32(p_bpb->clu_count) + 2; - /* because the cluster index starts with 2 */ - - p_fs->vol_type = EXFAT; - p_fs->vol_id = GET32(p_bpb->vol_serial); - - p_fs->root_dir = GET32(p_bpb->root_cluster); - p_fs->dentries_in_root = 0; - p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - - DENTRY_SIZE_BITS); - - p_fs->vol_flag = (u32)GET16(p_bpb->vol_flags); - p_fs->clu_srch_ptr = 2; - p_fs->used_clusters = UINT_MAX; - - return 0; -} - -s32 create_dir(struct inode *inode, struct chain_t *p_dir, - struct uni_name_t *p_uniname, struct file_id_t *fid) -{ - s32 ret, dentry, num_entries; - u64 size; - struct chain_t clu; - struct dos_name_t dos_name; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, - &dos_name); - if (ret) - return ret; - - /* find_empty_entry must be called before alloc_cluster */ - dentry = find_empty_entry(inode, p_dir, num_entries); - if (dentry < 0) - return -ENOSPC; - - clu.dir = CLUSTER_32(~0); - clu.size = 0; - clu.flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; - - /* (1) allocate a cluster */ - ret = exfat_alloc_cluster(sb, 1, &clu); - if (ret < 0) - return ret; - else if (ret == 0) - return -ENOSPC; - - ret = clear_cluster(sb, clu.dir); - if (ret != 0) - return ret; - - size = p_fs->cluster_size; - - /* (2) update the directory entry */ - /* make sub-dir entry in parent directory */ - ret = exfat_init_dir_entry(sb, p_dir, dentry, TYPE_DIR, clu.dir, - size); - if (ret != 0) - return ret; - - ret = exfat_init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, - &dos_name); - if (ret != 0) - return ret; - - fid->dir.dir = p_dir->dir; - fid->dir.size = p_dir->size; - fid->dir.flags = p_dir->flags; - fid->entry = dentry; - - fid->attr = ATTR_SUBDIR; - fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; - fid->size = size; - fid->start_clu = clu.dir; - - fid->type = TYPE_DIR; - fid->rwoffset = 0; - fid->hint_last_off = -1; - - return 0; -} - -s32 create_file(struct inode *inode, struct chain_t *p_dir, - struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid) -{ - s32 ret, dentry, num_entries; - struct dos_name_t dos_name; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, - &dos_name); - if (ret) - return ret; - - /* find_empty_entry must be called before alloc_cluster() */ - dentry = find_empty_entry(inode, p_dir, num_entries); - if (dentry < 0) - return -ENOSPC; - - /* (1) update the directory entry */ - /* fill the dos name directory entry information of the created file. - * the first cluster is not determined yet. (0) - */ - ret = exfat_init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode, - CLUSTER_32(0), 0); - if (ret != 0) - return ret; - - ret = exfat_init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, - &dos_name); - if (ret != 0) - return ret; - - fid->dir.dir = p_dir->dir; - fid->dir.size = p_dir->size; - fid->dir.flags = p_dir->flags; - fid->entry = dentry; - - fid->attr = ATTR_ARCHIVE | mode; - fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; - fid->size = 0; - fid->start_clu = CLUSTER_32(~0); - - fid->type = TYPE_FILE; - fid->rwoffset = 0; - fid->hint_last_off = -1; - - return 0; -} - -void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry) -{ - s32 num_entries; - sector_t sector; - struct dentry_t *ep; - struct super_block *sb = inode->i_sb; - - ep = get_entry_in_dir(sb, p_dir, entry, §or); - if (!ep) - return; - - exfat_buf_lock(sb, sector); - - /* exfat_buf_lock() before call count_ext_entries() */ - num_entries = exfat_count_ext_entries(sb, p_dir, entry, ep); - if (num_entries < 0) { - exfat_buf_unlock(sb, sector); - return; - } - num_entries++; - - exfat_buf_unlock(sb, sector); - - /* (1) update the directory entry */ - exfat_delete_dir_entry(sb, p_dir, entry, 0, num_entries); -} - -s32 exfat_rename_file(struct inode *inode, struct chain_t *p_dir, s32 oldentry, - struct uni_name_t *p_uniname, struct file_id_t *fid) -{ - s32 ret, newentry = -1, num_old_entries, num_new_entries; - sector_t sector_old, sector_new; - struct dos_name_t dos_name; - struct dentry_t *epold, *epnew; - struct super_block *sb = inode->i_sb; - - epold = get_entry_in_dir(sb, p_dir, oldentry, §or_old); - if (!epold) - return -ENOENT; - - exfat_buf_lock(sb, sector_old); - - /* exfat_buf_lock() before call count_ext_entries() */ - num_old_entries = exfat_count_ext_entries(sb, p_dir, oldentry, - epold); - if (num_old_entries < 0) { - exfat_buf_unlock(sb, sector_old); - return -ENOENT; - } - num_old_entries++; - - ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, - &num_new_entries, &dos_name); - if (ret) { - exfat_buf_unlock(sb, sector_old); - return ret; - } - - if (num_old_entries < num_new_entries) { - newentry = find_empty_entry(inode, p_dir, num_new_entries); - if (newentry < 0) { - exfat_buf_unlock(sb, sector_old); - return -ENOSPC; - } - - epnew = get_entry_in_dir(sb, p_dir, newentry, §or_new); - if (!epnew) { - exfat_buf_unlock(sb, sector_old); - return -ENOENT; - } - - memcpy((void *)epnew, (void *)epold, DENTRY_SIZE); - if (exfat_get_entry_type(epnew) == TYPE_FILE) { - exfat_set_entry_attr(epnew, - exfat_get_entry_attr(epnew) | - ATTR_ARCHIVE); - fid->attr |= ATTR_ARCHIVE; - } - exfat_buf_modify(sb, sector_new); - exfat_buf_unlock(sb, sector_old); - - epold = get_entry_in_dir(sb, p_dir, oldentry + 1, - §or_old); - exfat_buf_lock(sb, sector_old); - epnew = get_entry_in_dir(sb, p_dir, newentry + 1, - §or_new); - - if (!epold || !epnew) { - exfat_buf_unlock(sb, sector_old); - return -ENOENT; - } - - memcpy((void *)epnew, (void *)epold, DENTRY_SIZE); - exfat_buf_modify(sb, sector_new); - exfat_buf_unlock(sb, sector_old); - - ret = exfat_init_ext_entry(sb, p_dir, newentry, - num_new_entries, p_uniname, - &dos_name); - if (ret != 0) - return ret; - - exfat_delete_dir_entry(sb, p_dir, oldentry, 0, - num_old_entries); - fid->entry = newentry; - } else { - if (exfat_get_entry_type(epold) == TYPE_FILE) { - exfat_set_entry_attr(epold, - exfat_get_entry_attr(epold) | - ATTR_ARCHIVE); - fid->attr |= ATTR_ARCHIVE; - } - exfat_buf_modify(sb, sector_old); - exfat_buf_unlock(sb, sector_old); - - ret = exfat_init_ext_entry(sb, p_dir, oldentry, - num_new_entries, p_uniname, - &dos_name); - if (ret != 0) - return ret; - - exfat_delete_dir_entry(sb, p_dir, oldentry, num_new_entries, - num_old_entries); - } - - return 0; -} - -s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry, - struct chain_t *p_newdir, struct uni_name_t *p_uniname, - struct file_id_t *fid) -{ - s32 ret, newentry, num_new_entries, num_old_entries; - sector_t sector_mov, sector_new; - struct dos_name_t dos_name; - struct dentry_t *epmov, *epnew; - struct super_block *sb = inode->i_sb; - - epmov = get_entry_in_dir(sb, p_olddir, oldentry, §or_mov); - if (!epmov) - return -ENOENT; - - /* check if the source and target directory is the same */ - if (exfat_get_entry_type(epmov) == TYPE_DIR && - exfat_get_entry_clu0(epmov) == p_newdir->dir) - return -EINVAL; - - exfat_buf_lock(sb, sector_mov); - - /* exfat_buf_lock() before call count_ext_entries() */ - num_old_entries = exfat_count_ext_entries(sb, p_olddir, oldentry, - epmov); - if (num_old_entries < 0) { - exfat_buf_unlock(sb, sector_mov); - return -ENOENT; - } - num_old_entries++; - - ret = get_num_entries_and_dos_name(sb, p_newdir, p_uniname, - &num_new_entries, &dos_name); - if (ret) { - exfat_buf_unlock(sb, sector_mov); - return ret; - } - - newentry = find_empty_entry(inode, p_newdir, num_new_entries); - if (newentry < 0) { - exfat_buf_unlock(sb, sector_mov); - return -ENOSPC; - } - - epnew = get_entry_in_dir(sb, p_newdir, newentry, §or_new); - if (!epnew) { - exfat_buf_unlock(sb, sector_mov); - return -ENOENT; - } - - memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE); - if (exfat_get_entry_type(epnew) == TYPE_FILE) { - exfat_set_entry_attr(epnew, exfat_get_entry_attr(epnew) | - ATTR_ARCHIVE); - fid->attr |= ATTR_ARCHIVE; - } - exfat_buf_modify(sb, sector_new); - exfat_buf_unlock(sb, sector_mov); - - epmov = get_entry_in_dir(sb, p_olddir, oldentry + 1, - §or_mov); - exfat_buf_lock(sb, sector_mov); - epnew = get_entry_in_dir(sb, p_newdir, newentry + 1, - §or_new); - if (!epmov || !epnew) { - exfat_buf_unlock(sb, sector_mov); - return -ENOENT; - } - - memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE); - exfat_buf_modify(sb, sector_new); - exfat_buf_unlock(sb, sector_mov); - - ret = exfat_init_ext_entry(sb, p_newdir, newentry, num_new_entries, - p_uniname, &dos_name); - if (ret != 0) - return ret; - - exfat_delete_dir_entry(sb, p_olddir, oldentry, 0, num_old_entries); - - fid->dir.dir = p_newdir->dir; - fid->dir.size = p_newdir->size; - fid->dir.flags = p_newdir->flags; - - fid->entry = newentry; - - return 0; -} - -/* - * Sector Read/Write Functions - */ - -int sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, - bool read) -{ - s32 ret = -EIO; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if ((sec >= (p_fs->PBR_sector + p_fs->num_sectors)) && - (p_fs->num_sectors > 0)) { - pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n", - __func__, (unsigned long long)sec); - fs_error(sb); - return ret; - } - - if (!p_fs->dev_ejected) { - ret = exfat_bdev_read(sb, sec, bh, 1, read); - if (ret != 0) - p_fs->dev_ejected = 1; - } - - return ret; -} - -int sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, - bool sync) -{ - s32 ret = -EIO; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if (sec >= (p_fs->PBR_sector + p_fs->num_sectors) && - (p_fs->num_sectors > 0)) { - pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n", - __func__, (unsigned long long)sec); - fs_error(sb); - return ret; - } - - if (!bh) { - pr_err("[EXFAT] %s: bh is NULL!\n", __func__); - fs_error(sb); - return ret; - } - - if (!p_fs->dev_ejected) { - ret = exfat_bdev_write(sb, sec, bh, 1, sync); - if (ret != 0) - p_fs->dev_ejected = 1; - } - - return ret; -} - -int multi_sector_read(struct super_block *sb, sector_t sec, - struct buffer_head **bh, s32 num_secs, bool read) -{ - s32 ret = -EIO; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if (((sec + num_secs) > (p_fs->PBR_sector + p_fs->num_sectors)) && - (p_fs->num_sectors > 0)) { - pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n", - __func__, (unsigned long long)sec, num_secs); - fs_error(sb); - return ret; - } - - if (!p_fs->dev_ejected) { - ret = exfat_bdev_read(sb, sec, bh, num_secs, read); - if (ret != 0) - p_fs->dev_ejected = 1; - } - - return ret; -} - -int multi_sector_write(struct super_block *sb, sector_t sec, - struct buffer_head *bh, s32 num_secs, bool sync) -{ - s32 ret = -EIO; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if ((sec + num_secs) > (p_fs->PBR_sector + p_fs->num_sectors) && - (p_fs->num_sectors > 0)) { - pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n", - __func__, (unsigned long long)sec, num_secs); - fs_error(sb); - return ret; - } - if (!bh) { - pr_err("[EXFAT] %s: bh is NULL!\n", __func__); - fs_error(sb); - return ret; - } - - if (!p_fs->dev_ejected) { - ret = exfat_bdev_write(sb, sec, bh, num_secs, sync); - if (ret != 0) - p_fs->dev_ejected = 1; - } - - return ret; -} diff --git a/drivers/staging/exfat/exfat_nls.c b/drivers/staging/exfat/exfat_nls.c deleted file mode 100644 index 91e8b0c4dce7..000000000000 --- a/drivers/staging/exfat/exfat_nls.c +++ /dev/null @@ -1,212 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. - */ - -#include <linux/string.h> -#include <linux/nls.h> -#include "exfat.h" - -static u16 bad_uni_chars[] = { - /* " * / : < > ? \ | */ - 0x0022, 0x002A, 0x002F, 0x003A, - 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, - 0 -}; - -static int convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, - bool *lossy) -{ - int len; - - *uni = 0x0; - - if (ch[0] < 0x80) { - *uni = (u16)ch[0]; - return 1; - } - - len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni); - if (len < 0) { - /* conversion failed */ - pr_info("%s: fail to use nls\n", __func__); - if (lossy) - *lossy = true; - *uni = (u16)'_'; - if (!strcmp(nls->charset, "utf8")) - return 1; - else - return 2; - } - - return len; -} - -static int convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, - bool *lossy) -{ - int len; - - ch[0] = 0x0; - - if (uni < 0x0080) { - ch[0] = (u8)uni; - return 1; - } - - len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE); - if (len < 0) { - /* conversion failed */ - pr_info("%s: fail to use nls\n", __func__); - if (lossy) - *lossy = true; - ch[0] = '_'; - return 1; - } - - return len; -} - -u16 nls_upper(struct super_block *sb, u16 a) -{ - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - if (EXFAT_SB(sb)->options.casesensitive) - return a; - if (p_fs->vol_utbl && p_fs->vol_utbl[get_col_index(a)]) - return p_fs->vol_utbl[get_col_index(a)][get_row_index(a)]; - else - return a; -} - -static u16 *nls_wstrchr(u16 *str, u16 wchar) -{ - while (*str) { - if (*(str++) == wchar) - return str; - } - - return NULL; -} - -int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b) -{ - int i; - - for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) { - if (nls_upper(sb, *a) != nls_upper(sb, *b)) - return 1; - if (*a == 0x0) - return 0; - } - return 0; -} - -void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, - struct uni_name_t *p_uniname) -{ - int i, j, len; - u8 buf[MAX_CHARSET_SIZE]; - u16 *uniname = p_uniname->name; - struct nls_table *nls = EXFAT_SB(sb)->nls_io; - - if (!nls) { - len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, - UTF16_HOST_ENDIAN, p_cstring, - MAX_NAME_LENGTH); - p_cstring[len] = 0; - return; - } - - i = 0; - while (i < (MAX_NAME_LENGTH - 1)) { - if (*uniname == (u16)'\0') - break; - - len = convert_uni_to_ch(nls, buf, *uniname, NULL); - - if (len > 1) { - for (j = 0; j < len; j++) - *p_cstring++ = (char)*(buf + j); - } else { /* len == 1 */ - *p_cstring++ = (char)*buf; - } - - uniname++; - i++; - } - - *p_cstring = '\0'; -} - -void nls_cstring_to_uniname(struct super_block *sb, - struct uni_name_t *p_uniname, u8 *p_cstring, - bool *p_lossy) -{ - int i, j; - bool lossy = false; - u8 *end_of_name; - u8 upname[MAX_NAME_LENGTH * 2]; - u16 *uniname = p_uniname->name; - struct nls_table *nls = EXFAT_SB(sb)->nls_io; - - /* strip all trailing spaces */ - end_of_name = p_cstring + strlen(p_cstring); - - while (*(--end_of_name) == ' ') { - if (end_of_name < p_cstring) - break; - } - *(++end_of_name) = '\0'; - - if (strcmp(p_cstring, ".") && strcmp(p_cstring, "..")) { - /* strip all trailing periods */ - while (*(--end_of_name) == '.') { - if (end_of_name < p_cstring) - break; - } - *(++end_of_name) = '\0'; - } - - if (*p_cstring == '\0') - lossy = true; - - if (!nls) { - i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH, - UTF16_HOST_ENDIAN, uniname, - MAX_NAME_LENGTH); - for (j = 0; j < i; j++) - SET16_A(upname + j * 2, nls_upper(sb, uniname[j])); - uniname[i] = '\0'; - } else { - i = 0; - j = 0; - while (j < (MAX_NAME_LENGTH - 1)) { - if (*(p_cstring + i) == '\0') - break; - - i += convert_ch_to_uni(nls, uniname, - (u8 *)(p_cstring + i), &lossy); - - if ((*uniname < 0x0020) || - nls_wstrchr(bad_uni_chars, *uniname)) - lossy = true; - - SET16_A(upname + j * 2, nls_upper(sb, *uniname)); - - uniname++; - j++; - } - - if (*(p_cstring + i) != '\0') - lossy = true; - *uniname = (u16)'\0'; - } - - p_uniname->name_len = j; - p_uniname->name_hash = calc_checksum_2byte(upname, j << 1, 0, - CS_DEFAULT); - - if (p_lossy) - *p_lossy = lossy; -} diff --git a/drivers/staging/exfat/exfat_super.c b/drivers/staging/exfat/exfat_super.c deleted file mode 100644 index b81d2a87b82e..000000000000 --- a/drivers/staging/exfat/exfat_super.c +++ /dev/null @@ -1,3883 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/time.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/seq_file.h> -#include <linux/pagemap.h> -#include <linux/mpage.h> -#include <linux/buffer_head.h> -#include <linux/exportfs.h> -#include <linux/mount.h> -#include <linux/vfs.h> -#include <linux/aio.h> -#include <linux/iversion.h> -#include <linux/parser.h> -#include <linux/uio.h> -#include <linux/writeback.h> -#include <linux/log2.h> -#include <linux/hash.h> -#include <linux/backing-dev.h> -#include <linux/sched.h> -#include <linux/fs_struct.h> -#include <linux/namei.h> -#include <linux/random.h> -#include <linux/string.h> -#include <linux/nls.h> -#include <linux/mutex.h> -#include <linux/swap.h> - -#define EXFAT_VERSION "1.3.0" - -#include "exfat.h" - -static struct kmem_cache *exfat_inode_cachep; - -static int exfat_default_codepage = CONFIG_STAGING_EXFAT_DEFAULT_CODEPAGE; -static char exfat_default_iocharset[] = CONFIG_STAGING_EXFAT_DEFAULT_IOCHARSET; - -#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)) - -static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos); -static int exfat_sync_inode(struct inode *inode); -static struct inode *exfat_build_inode(struct super_block *sb, - struct file_id_t *fid, loff_t i_pos); -static int exfat_write_inode(struct inode *inode, - struct writeback_control *wbc); -static void exfat_write_super(struct super_block *sb); - -#define UNIX_SECS_1980 315532800L -#define UNIX_SECS_2108 4354819200L - -/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ -static void exfat_time_fat2unix(struct timespec64 *ts, struct date_time_t *tp) -{ - ts->tv_sec = mktime64(tp->Year + 1980, tp->Month + 1, tp->Day, - tp->Hour, tp->Minute, tp->Second); - - ts->tv_nsec = tp->MilliSecond * NSEC_PER_MSEC; -} - -/* Convert linear UNIX date to a FAT time/date pair. */ -static void exfat_time_unix2fat(struct timespec64 *ts, struct date_time_t *tp) -{ - time64_t second = ts->tv_sec; - struct tm tm; - - time64_to_tm(second, 0, &tm); - - if (second < UNIX_SECS_1980) { - tp->MilliSecond = 0; - tp->Second = 0; - tp->Minute = 0; - tp->Hour = 0; - tp->Day = 1; - tp->Month = 1; - tp->Year = 0; - return; - } - - if (second >= UNIX_SECS_2108) { - tp->MilliSecond = 999; - tp->Second = 59; - tp->Minute = 59; - tp->Hour = 23; - tp->Day = 31; - tp->Month = 12; - tp->Year = 127; - return; - } - - tp->MilliSecond = ts->tv_nsec / NSEC_PER_MSEC; - tp->Second = tm.tm_sec; - tp->Minute = tm.tm_min; - tp->Hour = tm.tm_hour; - tp->Day = tm.tm_mday; - tp->Month = tm.tm_mon + 1; - tp->Year = tm.tm_year + 1900 - 1980; -} - -struct timestamp_t *tm_current(struct timestamp_t *tp) -{ - time64_t second = ktime_get_real_seconds(); - struct tm tm; - - time64_to_tm(second, 0, &tm); - - if (second < UNIX_SECS_1980) { - tp->sec = 0; - tp->min = 0; - tp->hour = 0; - tp->day = 1; - tp->mon = 1; - tp->year = 0; - return tp; - } - - if (second >= UNIX_SECS_2108) { - tp->sec = 59; - tp->min = 59; - tp->hour = 23; - tp->day = 31; - tp->mon = 12; - tp->year = 127; - return tp; - } - - tp->sec = tm.tm_sec; - tp->min = tm.tm_min; - tp->hour = tm.tm_hour; - tp->day = tm.tm_mday; - tp->mon = tm.tm_mon + 1; - tp->year = tm.tm_year + 1900 - 1980; - - return tp; -} - -static void __lock_super(struct super_block *sb) -{ - struct exfat_sb_info *sbi = EXFAT_SB(sb); - - mutex_lock(&sbi->s_lock); -} - -static void __unlock_super(struct super_block *sb) -{ - struct exfat_sb_info *sbi = EXFAT_SB(sb); - - mutex_unlock(&sbi->s_lock); -} - -static int __is_sb_dirty(struct super_block *sb) -{ - struct exfat_sb_info *sbi = EXFAT_SB(sb); - - return sbi->s_dirt; -} - -static void __set_sb_clean(struct super_block *sb) -{ - struct exfat_sb_info *sbi = EXFAT_SB(sb); - - sbi->s_dirt = 0; -} - -static int __exfat_revalidate(struct dentry *dentry) -{ - return 0; -} - -static int exfat_revalidate(struct dentry *dentry, unsigned int flags) -{ - if (flags & LOOKUP_RCU) - return -ECHILD; - - if (dentry->d_inode) - return 1; - return __exfat_revalidate(dentry); -} - -static int exfat_revalidate_ci(struct dentry *dentry, unsigned int flags) -{ - if (flags & LOOKUP_RCU) - return -ECHILD; - - if (dentry->d_inode) - return 1; - - if (!flags) - return 0; - - if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) - return 0; - - return __exfat_revalidate(dentry); -} - -static unsigned int __exfat_striptail_len(unsigned int len, const char *name) -{ - while (len && name[len - 1] == '.') - len--; - return len; -} - -static unsigned int exfat_striptail_len(const struct qstr *qstr) -{ - return __exfat_striptail_len(qstr->len, qstr->name); -} - -static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) -{ - qstr->hash = full_name_hash(dentry, qstr->name, - exfat_striptail_len(qstr)); - return 0; -} - -static int exfat_d_hashi(const struct dentry *dentry, struct qstr *qstr) -{ - struct super_block *sb = dentry->d_sb; - const unsigned char *name; - unsigned int len; - unsigned long hash; - - name = qstr->name; - len = exfat_striptail_len(qstr); - - hash = init_name_hash(dentry); - while (len--) - hash = partial_name_hash(nls_upper(sb, *name++), hash); - qstr->hash = end_name_hash(hash); - - return 0; -} - -static int exfat_cmpi(const struct dentry *dentry, unsigned int len, - const char *str, const struct qstr *name) -{ - struct nls_table *t = EXFAT_SB(dentry->d_sb)->nls_io; - unsigned int alen, blen; - - alen = exfat_striptail_len(name); - blen = __exfat_striptail_len(len, str); - if (alen == blen) { - if (!t) { - if (strncasecmp(name->name, str, alen) == 0) - return 0; - } else { - if (nls_strnicmp(t, name->name, str, alen) == 0) - return 0; - } - } - return 1; -} - -static int exfat_cmp(const struct dentry *dentry, unsigned int len, - const char *str, const struct qstr *name) -{ - unsigned int alen, blen; - - alen = exfat_striptail_len(name); - blen = __exfat_striptail_len(len, str); - if (alen == blen) { - if (strncmp(name->name, str, alen) == 0) - return 0; - } - return 1; -} - -static const struct dentry_operations exfat_ci_dentry_ops = { - .d_revalidate = exfat_revalidate_ci, - .d_hash = exfat_d_hashi, - .d_compare = exfat_cmpi, -}; - -static const struct dentry_operations exfat_dentry_ops = { - .d_revalidate = exfat_revalidate, - .d_hash = exfat_d_hash, - .d_compare = exfat_cmp, -}; - -static DEFINE_MUTEX(z_mutex); - -static inline void fs_sync(struct super_block *sb, bool do_sync) -{ - if (do_sync) - exfat_bdev_sync(sb); -} - -/* - * 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) & 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, u32 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; - 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) -{ - if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222)) - return (EXFAT_I(inode)->fid.attr) | ATTR_READONLY; - else - return EXFAT_I(inode)->fid.attr; -} - -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); -} - -static int ffsMountVol(struct super_block *sb) -{ - int i, ret; - struct pbr_sector_t *p_pbr; - struct buffer_head *tmp_bh = NULL; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - pr_info("[EXFAT] trying to mount...\n"); - - mutex_lock(&z_mutex); - - exfat_buf_init(sb); - - mutex_init(&p_fs->v_mutex); - p_fs->dev_ejected = 0; - - /* open the block device */ - exfat_bdev_open(sb); - - if (p_bd->sector_size < sb->s_blocksize) { - printk(KERN_INFO "EXFAT: mount failed - sector size %d less than blocksize %ld\n", - p_bd->sector_size, sb->s_blocksize); - ret = -EINVAL; - goto out; - } - if (p_bd->sector_size > sb->s_blocksize) - sb_set_blocksize(sb, p_bd->sector_size); - - /* read Sector 0 */ - if (sector_read(sb, 0, &tmp_bh, 1) != 0) { - ret = -EIO; - goto out; - } - - p_fs->PBR_sector = 0; - - p_pbr = (struct pbr_sector_t *)tmp_bh->b_data; - - /* check the validity of PBR */ - if (GET16_A(p_pbr->signature) != PBR_SIGNATURE) { - brelse(tmp_bh); - exfat_bdev_close(sb); - ret = -EFSCORRUPTED; - goto out; - } - - /* fill fs_struct */ - for (i = 0; i < 53; i++) - if (p_pbr->bpb[i]) - break; - - if (i < 53) { - /* Not sure how we'd get here, but complain if it does */ - ret = -EINVAL; - pr_info("EXFAT: Attempted to mount VFAT filesystem\n"); - goto out; - } else { - ret = exfat_mount(sb, p_pbr); - } - - brelse(tmp_bh); - - if (ret) { - exfat_bdev_close(sb); - goto out; - } - - ret = load_alloc_bitmap(sb); - if (ret) { - exfat_bdev_close(sb); - goto out; - } - ret = load_upcase_table(sb); - if (ret) { - free_alloc_bitmap(sb); - exfat_bdev_close(sb); - goto out; - } - - if (p_fs->dev_ejected) { - free_upcase_table(sb); - free_alloc_bitmap(sb); - exfat_bdev_close(sb); - ret = -EIO; - goto out; - } - - pr_info("[EXFAT] mounted successfully\n"); - -out: - mutex_unlock(&z_mutex); - - return ret; -} - -static int ffsUmountVol(struct super_block *sb) -{ - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - int err = 0; - - pr_info("[EXFAT] trying to unmount...\n"); - - mutex_lock(&z_mutex); - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - fs_sync(sb, true); - fs_set_vol_flags(sb, VOL_CLEAN); - - free_upcase_table(sb); - free_alloc_bitmap(sb); - - exfat_fat_release_all(sb); - exfat_buf_release_all(sb); - - /* close the block device */ - exfat_bdev_close(sb); - - if (p_fs->dev_ejected) { - pr_info("[EXFAT] unmounted with media errors. Device is already ejected.\n"); - err = -EIO; - } - - exfat_buf_shutdown(sb); - - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - mutex_unlock(&z_mutex); - - pr_info("[EXFAT] unmounted successfully\n"); - - return err; -} - -static int ffsGetVolInfo(struct super_block *sb, struct vol_info_t *info) -{ - int err = 0; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - /* check the validity of pointer parameters */ - if (!info) - return -EINVAL; - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - if (p_fs->used_clusters == UINT_MAX) - p_fs->used_clusters = exfat_count_used_clusters(sb); - - info->FatType = p_fs->vol_type; - info->ClusterSize = p_fs->cluster_size; - info->NumClusters = p_fs->num_clusters - 2; /* clu 0 & 1 */ - info->UsedClusters = p_fs->used_clusters; - info->FreeClusters = info->NumClusters - info->UsedClusters; - - if (p_fs->dev_ejected) - err = -EIO; - - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return err; -} - -static int ffsSyncVol(struct super_block *sb, bool do_sync) -{ - int err = 0; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - /* synchronize the file system */ - fs_sync(sb, do_sync); - fs_set_vol_flags(sb, VOL_CLEAN); - - if (p_fs->dev_ejected) - err = -EIO; - - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return err; -} - -/*----------------------------------------------------------------------*/ -/* File Operation Functions */ -/*----------------------------------------------------------------------*/ - -static int ffsLookupFile(struct inode *inode, char *path, struct file_id_t *fid) -{ - int ret, dentry, num_entries; - struct chain_t dir; - struct uni_name_t uni_name; - struct dos_name_t dos_name; - struct dentry_t *ep, *ep2; - struct entry_set_cache_t *es = NULL; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - pr_debug("%s entered\n", __func__); - - /* check the validity of pointer parameters */ - if (!fid || !path || (*path == '\0')) - return -EINVAL; - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - /* check the validity of directory name in the given pathname */ - ret = resolve_path(inode, path, &dir, &uni_name); - if (ret) - goto out; - - ret = get_num_entries_and_dos_name(sb, &dir, &uni_name, &num_entries, - &dos_name); - if (ret) - goto out; - - /* search the file name for directories */ - dentry = exfat_find_dir_entry(sb, &dir, &uni_name, num_entries, - &dos_name, TYPE_ALL); - if (dentry < -1) { - ret = -ENOENT; - goto out; - } - - fid->dir.dir = dir.dir; - fid->dir.size = dir.size; - fid->dir.flags = dir.flags; - fid->entry = dentry; - - if (dentry == -1) { - fid->type = TYPE_DIR; - fid->rwoffset = 0; - fid->hint_last_off = -1; - - fid->attr = ATTR_SUBDIR; - fid->flags = 0x01; - fid->size = 0; - fid->start_clu = p_fs->root_dir; - } else { - es = get_entry_set_in_dir(sb, &dir, dentry, - ES_2_ENTRIES, &ep); - if (!es) { - ret = -ENOENT; - goto out; - } - ep2 = ep + 1; - - fid->type = exfat_get_entry_type(ep); - fid->rwoffset = 0; - fid->hint_last_off = -1; - fid->attr = exfat_get_entry_attr(ep); - - fid->size = exfat_get_entry_size(ep2); - if ((fid->type == TYPE_FILE) && (fid->size == 0)) { - fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; - fid->start_clu = CLUSTER_32(~0); - } else { - fid->flags = exfat_get_entry_flag(ep2); - fid->start_clu = exfat_get_entry_clu0(ep2); - } - - release_entry_set(es); - } - - if (p_fs->dev_ejected) - ret = -EIO; -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} - -static int ffsCreateFile(struct inode *inode, char *path, u8 mode, - struct file_id_t *fid) -{ - struct chain_t dir; - struct uni_name_t uni_name; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - int ret = 0; - - /* check the validity of pointer parameters */ - if (!fid || !path || (*path == '\0')) - return -EINVAL; - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - /* check the validity of directory name in the given pathname */ - ret = resolve_path(inode, path, &dir, &uni_name); - if (ret) - goto out; - - fs_set_vol_flags(sb, VOL_DIRTY); - - /* create a new file */ - ret = create_file(inode, &dir, &uni_name, mode, fid); - -#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC - fs_sync(sb, true); - fs_set_vol_flags(sb, VOL_CLEAN); -#endif - - if (p_fs->dev_ejected) - ret = -EIO; - -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} - -static int ffsReadFile(struct inode *inode, struct file_id_t *fid, void *buffer, - u64 count, u64 *rcount) -{ - s32 offset, sec_offset, clu_offset; - u32 clu; - int ret = 0; - sector_t LogSector; - u64 oneblkread, read_bytes; - struct buffer_head *tmp_bh = NULL; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - /* check the validity of the given file id */ - if (!fid) - return -EINVAL; - - /* check the validity of pointer parameters */ - if (!buffer) - return -EINVAL; - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - /* check if the given file ID is opened */ - if (fid->type != TYPE_FILE) { - ret = -EPERM; - goto out; - } - - if (fid->rwoffset > fid->size) - fid->rwoffset = fid->size; - - if (count > (fid->size - fid->rwoffset)) - count = fid->size - fid->rwoffset; - - if (count == 0) { - if (rcount) - *rcount = 0; - ret = 0; - goto out; - } - - read_bytes = 0; - - while (count > 0) { - clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); - clu = fid->start_clu; - - if (fid->flags == 0x03) { - clu += clu_offset; - } else { - /* hint information */ - if ((clu_offset > 0) && (fid->hint_last_off > 0) && - (clu_offset >= fid->hint_last_off)) { - clu_offset -= fid->hint_last_off; - clu = fid->hint_last_clu; - } - - while (clu_offset > 0) { - /* clu = exfat_fat_read(sb, clu); */ - if (exfat_fat_read(sb, clu, &clu) == -1) { - ret = -EIO; - goto out; - } - - clu_offset--; - } - } - - /* hint information */ - fid->hint_last_off = (s32)(fid->rwoffset >> - p_fs->cluster_size_bits); - fid->hint_last_clu = clu; - - /* byte offset in cluster */ - offset = (s32)(fid->rwoffset & (p_fs->cluster_size - 1)); - - /* sector offset in cluster */ - sec_offset = offset >> p_bd->sector_size_bits; - - /* byte offset in sector */ - offset &= p_bd->sector_size_mask; - - LogSector = START_SECTOR(clu) + sec_offset; - - oneblkread = (u64)(p_bd->sector_size - offset); - if (oneblkread > count) - oneblkread = count; - - if ((offset == 0) && (oneblkread == p_bd->sector_size)) { - if (sector_read(sb, LogSector, &tmp_bh, 1) != - 0) - goto err_out; - memcpy((char *)buffer + read_bytes, - (char *)tmp_bh->b_data, (s32)oneblkread); - } else { - if (sector_read(sb, LogSector, &tmp_bh, 1) != - 0) - goto err_out; - memcpy((char *)buffer + read_bytes, - (char *)tmp_bh->b_data + offset, - (s32)oneblkread); - } - count -= oneblkread; - read_bytes += oneblkread; - fid->rwoffset += oneblkread; - } - brelse(tmp_bh); - -/* How did this ever work and not leak a brlse()?? */ -err_out: - /* set the size of read bytes */ - if (rcount) - *rcount = read_bytes; - - if (p_fs->dev_ejected) - ret = -EIO; - -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} - -static int ffsWriteFile(struct inode *inode, struct file_id_t *fid, - void *buffer, u64 count, u64 *wcount) -{ - bool modified = false; - s32 offset, sec_offset, clu_offset; - s32 num_clusters, num_alloc, num_alloced = (s32)~0; - int ret = 0; - u32 clu, last_clu; - sector_t LogSector; - u64 oneblkwrite, write_bytes; - struct chain_t new_clu; - struct timestamp_t tm; - struct dentry_t *ep, *ep2; - struct entry_set_cache_t *es = NULL; - struct buffer_head *tmp_bh = NULL; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - - /* check the validity of the given file id */ - if (!fid) - return -EINVAL; - - /* check the validity of pointer parameters */ - if (!buffer) - return -EINVAL; - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - /* check if the given file ID is opened */ - if (fid->type != TYPE_FILE) { - ret = -EPERM; - goto out; - } - - if (fid->rwoffset > fid->size) - fid->rwoffset = fid->size; - - if (count == 0) { - if (wcount) - *wcount = 0; - ret = 0; - goto out; - } - - fs_set_vol_flags(sb, VOL_DIRTY); - - if (fid->size == 0) - num_clusters = 0; - else - num_clusters = (s32)((fid->size - 1) >> - p_fs->cluster_size_bits) + 1; - - write_bytes = 0; - - while (count > 0) { - clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); - clu = fid->start_clu; - last_clu = fid->start_clu; - - if (fid->flags == 0x03) { - if ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { - last_clu += clu_offset - 1; - - if (clu_offset == num_clusters) - clu = CLUSTER_32(~0); - else - clu += clu_offset; - } - } else { - /* hint information */ - if ((clu_offset > 0) && (fid->hint_last_off > 0) && - (clu_offset >= fid->hint_last_off)) { - clu_offset -= fid->hint_last_off; - clu = fid->hint_last_clu; - } - - while ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { - last_clu = clu; - /* clu = exfat_fat_read(sb, clu); */ - if (exfat_fat_read(sb, clu, &clu) == -1) { - ret = -EIO; - goto out; - } - clu_offset--; - } - } - - if (clu == CLUSTER_32(~0)) { - num_alloc = (s32)((count - 1) >> - p_fs->cluster_size_bits) + 1; - new_clu.dir = (last_clu == CLUSTER_32(~0)) ? - CLUSTER_32(~0) : last_clu + 1; - new_clu.size = 0; - new_clu.flags = fid->flags; - - /* (1) allocate a chain of clusters */ - num_alloced = exfat_alloc_cluster(sb, - num_alloc, - &new_clu); - if (num_alloced == 0) - break; - if (num_alloced < 0) { - ret = num_alloced; - goto out; - } - - /* (2) append to the FAT chain */ - if (last_clu == CLUSTER_32(~0)) { - if (new_clu.flags == 0x01) - fid->flags = 0x01; - fid->start_clu = new_clu.dir; - modified = true; - } else { - if (new_clu.flags != fid->flags) { - exfat_chain_cont_cluster(sb, - fid->start_clu, - num_clusters); - fid->flags = 0x01; - modified = true; - } - if (new_clu.flags == 0x01) - exfat_fat_write(sb, last_clu, new_clu.dir); - } - - num_clusters += num_alloced; - clu = new_clu.dir; - } - - /* hint information */ - fid->hint_last_off = (s32)(fid->rwoffset >> - p_fs->cluster_size_bits); - fid->hint_last_clu = clu; - - /* byte offset in cluster */ - offset = (s32)(fid->rwoffset & (p_fs->cluster_size - 1)); - - /* sector offset in cluster */ - sec_offset = offset >> p_bd->sector_size_bits; - - /* byte offset in sector */ - offset &= p_bd->sector_size_mask; - - LogSector = START_SECTOR(clu) + sec_offset; - - oneblkwrite = (u64)(p_bd->sector_size - offset); - if (oneblkwrite > count) - oneblkwrite = count; - - if ((offset == 0) && (oneblkwrite == p_bd->sector_size)) { - if (sector_read(sb, LogSector, &tmp_bh, 0) != - 0) - goto err_out; - memcpy((char *)tmp_bh->b_data, - (char *)buffer + write_bytes, (s32)oneblkwrite); - if (sector_write(sb, LogSector, tmp_bh, 0) != - 0) { - brelse(tmp_bh); - goto err_out; - } - } else { - if ((offset > 0) || - ((fid->rwoffset + oneblkwrite) < fid->size)) { - if (sector_read(sb, LogSector, &tmp_bh, 1) != - 0) - goto err_out; - } else { - if (sector_read(sb, LogSector, &tmp_bh, 0) != - 0) - goto err_out; - } - - memcpy((char *)tmp_bh->b_data + offset, - (char *)buffer + write_bytes, (s32)oneblkwrite); - if (sector_write(sb, LogSector, tmp_bh, 0) != - 0) { - brelse(tmp_bh); - goto err_out; - } - } - - count -= oneblkwrite; - write_bytes += oneblkwrite; - fid->rwoffset += oneblkwrite; - - fid->attr |= ATTR_ARCHIVE; - - if (fid->size < fid->rwoffset) { - fid->size = fid->rwoffset; - modified = true; - } - } - - brelse(tmp_bh); - - /* (3) update the direcoty entry */ - es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, - ES_ALL_ENTRIES, &ep); - if (!es) - goto err_out; - ep2 = ep + 1; - - exfat_set_entry_time(ep, tm_current(&tm), TM_MODIFY); - exfat_set_entry_attr(ep, fid->attr); - - if (modified) { - if (exfat_get_entry_flag(ep2) != fid->flags) - exfat_set_entry_flag(ep2, fid->flags); - - if (exfat_get_entry_size(ep2) != fid->size) - exfat_set_entry_size(ep2, fid->size); - - if (exfat_get_entry_clu0(ep2) != fid->start_clu) - exfat_set_entry_clu0(ep2, fid->start_clu); - } - - update_dir_checksum_with_entry_set(sb, es); - release_entry_set(es); - -#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC - fs_sync(sb, true); - fs_set_vol_flags(sb, VOL_CLEAN); -#endif - -err_out: - /* set the size of written bytes */ - if (wcount) - *wcount = write_bytes; - - if (num_alloced == 0) - ret = -ENOSPC; - - else if (p_fs->dev_ejected) - ret = -EIO; - -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} - -static int ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) -{ - s32 num_clusters; - u32 last_clu = CLUSTER_32(0); - int ret = 0; - struct chain_t clu; - struct timestamp_t tm; - struct dentry_t *ep, *ep2; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct file_id_t *fid = &(EXFAT_I(inode)->fid); - struct entry_set_cache_t *es = NULL; - - pr_debug("%s entered (inode %p size %llu)\n", __func__, inode, - new_size); - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - /* check if the given file ID is opened */ - if (fid->type != TYPE_FILE) { - ret = -EPERM; - goto out; - } - - if (fid->size != old_size) { - pr_err("[EXFAT] truncate : can't skip it because of size-mismatch(old:%lld->fid:%lld).\n", - old_size, fid->size); - } - - if (old_size <= new_size) { - ret = 0; - goto out; - } - - fs_set_vol_flags(sb, VOL_DIRTY); - - clu.dir = fid->start_clu; - clu.size = (s32)((old_size - 1) >> p_fs->cluster_size_bits) + 1; - clu.flags = fid->flags; - - if (new_size > 0) { - num_clusters = (s32)((new_size - 1) >> - p_fs->cluster_size_bits) + 1; - - if (clu.flags == 0x03) { - clu.dir += num_clusters; - } else { - while (num_clusters > 0) { - last_clu = clu.dir; - if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) { - ret = -EIO; - goto out; - } - num_clusters--; - } - } - - clu.size -= num_clusters; - } - - fid->size = new_size; - fid->attr |= ATTR_ARCHIVE; - if (new_size == 0) { - fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; - fid->start_clu = CLUSTER_32(~0); - } - - /* (1) update the directory entry */ - es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, - ES_ALL_ENTRIES, &ep); - if (!es) { - ret = -ENOENT; - goto out; - } - ep2 = ep + 1; - - exfat_set_entry_time(ep, tm_current(&tm), TM_MODIFY); - exfat_set_entry_attr(ep, fid->attr); - - exfat_set_entry_size(ep2, new_size); - if (new_size == 0) { - exfat_set_entry_flag(ep2, 0x01); - exfat_set_entry_clu0(ep2, CLUSTER_32(0)); - } - - update_dir_checksum_with_entry_set(sb, es); - release_entry_set(es); - - /* (2) cut off from the FAT chain */ - if (last_clu != CLUSTER_32(0)) { - if (fid->flags == 0x01) - exfat_fat_write(sb, last_clu, CLUSTER_32(~0)); - } - - /* (3) free the clusters */ - exfat_free_cluster(sb, &clu, 0); - - /* hint information */ - fid->hint_last_off = -1; - if (fid->rwoffset > fid->size) - fid->rwoffset = fid->size; - -#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC - fs_sync(sb, true); - fs_set_vol_flags(sb, VOL_CLEAN); -#endif - - if (p_fs->dev_ejected) - ret = -EIO; - -out: - pr_debug("%s exited (%d)\n", __func__, ret); - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} - -static void update_parent_info(struct file_id_t *fid, - struct inode *parent_inode) -{ - struct fs_info_t *p_fs = &(EXFAT_SB(parent_inode->i_sb)->fs_info); - struct file_id_t *parent_fid = &(EXFAT_I(parent_inode)->fid); - - if (unlikely((parent_fid->flags != fid->dir.flags) || - (parent_fid->size != - (fid->dir.size << p_fs->cluster_size_bits)) || - (parent_fid->start_clu != fid->dir.dir))) { - fid->dir.dir = parent_fid->start_clu; - fid->dir.flags = parent_fid->flags; - fid->dir.size = ((parent_fid->size + (p_fs->cluster_size - 1)) - >> p_fs->cluster_size_bits); - } -} - -static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid, - struct inode *new_parent_inode, struct dentry *new_dentry) -{ - s32 ret; - s32 dentry; - struct chain_t olddir, newdir; - struct chain_t *p_dir = NULL; - struct uni_name_t uni_name; - struct dentry_t *ep; - struct super_block *sb = old_parent_inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - u8 *new_path = (u8 *)new_dentry->d_name.name; - struct inode *new_inode = new_dentry->d_inode; - int num_entries; - struct file_id_t *new_fid = NULL; - s32 new_entry = 0; - - /* check the validity of the given file id */ - if (!fid) - return -EINVAL; - - /* check the validity of pointer parameters */ - if (!new_path || (*new_path == '\0')) - return -EINVAL; - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - update_parent_info(fid, old_parent_inode); - - olddir.dir = fid->dir.dir; - olddir.size = fid->dir.size; - olddir.flags = fid->dir.flags; - - dentry = fid->entry; - - /* check if the old file is "." or ".." */ - if (p_fs->vol_type != EXFAT) { - if ((olddir.dir != p_fs->root_dir) && (dentry < 2)) { - ret = -EPERM; - goto out2; - } - } - - ep = get_entry_in_dir(sb, &olddir, dentry, NULL); - if (!ep) { - ret = -ENOENT; - goto out2; - } - - if (exfat_get_entry_attr(ep) & ATTR_READONLY) { - ret = -EPERM; - goto out2; - } - - /* check whether new dir is existing directory and empty */ - if (new_inode) { - u32 entry_type; - - ret = -ENOENT; - new_fid = &EXFAT_I(new_inode)->fid; - - update_parent_info(new_fid, new_parent_inode); - - p_dir = &new_fid->dir; - new_entry = new_fid->entry; - ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); - if (!ep) - goto out; - - entry_type = exfat_get_entry_type(ep); - - if (entry_type == TYPE_DIR) { - struct chain_t new_clu; - - new_clu.dir = new_fid->start_clu; - new_clu.size = (s32)((new_fid->size - 1) >> - p_fs->cluster_size_bits) + 1; - new_clu.flags = new_fid->flags; - - if (!is_dir_empty(sb, &new_clu)) { - ret = -EEXIST; - goto out; - } - } - } - - /* check the validity of directory name in the given new pathname */ - ret = resolve_path(new_parent_inode, new_path, &newdir, &uni_name); - if (ret) - goto out2; - - fs_set_vol_flags(sb, VOL_DIRTY); - - if (olddir.dir == newdir.dir) - ret = exfat_rename_file(new_parent_inode, &olddir, dentry, - &uni_name, fid); - else - ret = move_file(new_parent_inode, &olddir, dentry, &newdir, - &uni_name, fid); - - if ((ret == 0) && new_inode) { - /* delete entries of new_dir */ - ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); - if (!ep) - goto out; - - num_entries = exfat_count_ext_entries(sb, p_dir, - new_entry, ep); - if (num_entries < 0) - goto out; - exfat_delete_dir_entry(sb, p_dir, new_entry, 0, - num_entries + 1); - } -out: -#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC - fs_sync(sb, true); - fs_set_vol_flags(sb, VOL_CLEAN); -#endif - - if (p_fs->dev_ejected) - ret = -EIO; -out2: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} - -static int ffsRemoveFile(struct inode *inode, struct file_id_t *fid) -{ - s32 dentry; - int ret = 0; - struct chain_t dir, clu_to_free; - struct dentry_t *ep; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - /* check the validity of the given file id */ - if (!fid) - return -EINVAL; - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - dir.dir = fid->dir.dir; - dir.size = fid->dir.size; - dir.flags = fid->dir.flags; - - dentry = fid->entry; - - ep = get_entry_in_dir(sb, &dir, dentry, NULL); - if (!ep) { - ret = -ENOENT; - goto out; - } - - if (exfat_get_entry_attr(ep) & ATTR_READONLY) { - ret = -EPERM; - goto out; - } - fs_set_vol_flags(sb, VOL_DIRTY); - - /* (1) update the directory entry */ - remove_file(inode, &dir, dentry); - - clu_to_free.dir = fid->start_clu; - clu_to_free.size = (s32)((fid->size - 1) >> p_fs->cluster_size_bits) + 1; - clu_to_free.flags = fid->flags; - - /* (2) free the clusters */ - exfat_free_cluster(sb, &clu_to_free, 0); - - fid->size = 0; - fid->start_clu = CLUSTER_32(~0); - fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; - -#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC - fs_sync(sb, true); - fs_set_vol_flags(sb, VOL_CLEAN); -#endif - - if (p_fs->dev_ejected) - ret = -EIO; -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} - -#if 0 -/* Not currently wired up */ -static int ffsSetAttr(struct inode *inode, u32 attr) -{ - u32 type; - int ret = 0; - sector_t sector = 0; - struct dentry_t *ep; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct file_id_t *fid = &(EXFAT_I(inode)->fid); - u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; - struct entry_set_cache_t *es = NULL; - - if (fid->attr == attr) { - if (p_fs->dev_ejected) - return -EIO; - return 0; - } - - if (is_dir) { - if ((fid->dir.dir == p_fs->root_dir) && - (fid->entry == -1)) { - if (p_fs->dev_ejected) - return -EIO; - return 0; - } - } - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - /* get the directory entry of given file */ - es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, - ES_ALL_ENTRIES, &ep); - if (!es) { - ret = -ENOENT; - goto out; - } - - type = exfat_get_entry_type(ep); - - if (((type == TYPE_FILE) && (attr & ATTR_SUBDIR)) || - ((type == TYPE_DIR) && (!(attr & ATTR_SUBDIR)))) { - if (p_fs->dev_ejected) - ret = -EIO; - else - ret = -EINVAL; - - release_entry_set(es); - goto out; - } - - fs_set_vol_flags(sb, VOL_DIRTY); - - /* set the file attribute */ - fid->attr = attr; - exfat_set_entry_attr(ep, attr); - - update_dir_checksum_with_entry_set(sb, es); - release_entry_set(es); - -#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC - fs_sync(sb, true); - fs_set_vol_flags(sb, VOL_CLEAN); -#endif - - if (p_fs->dev_ejected) - ret = -EIO; -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} -#endif - -static int ffsReadStat(struct inode *inode, struct dir_entry_t *info) -{ - s32 count; - int ret = 0; - struct chain_t dir; - struct uni_name_t uni_name; - struct timestamp_t tm; - struct dentry_t *ep, *ep2; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct file_id_t *fid = &(EXFAT_I(inode)->fid); - struct entry_set_cache_t *es = NULL; - u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; - - pr_debug("%s entered\n", __func__); - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - if (is_dir) { - if ((fid->dir.dir == p_fs->root_dir) && - (fid->entry == -1)) { - info->Attr = ATTR_SUBDIR; - memset((char *)&info->CreateTimestamp, 0, - sizeof(struct date_time_t)); - memset((char *)&info->ModifyTimestamp, 0, - sizeof(struct date_time_t)); - memset((char *)&info->AccessTimestamp, 0, - sizeof(struct date_time_t)); - strcpy(info->ShortName, "."); - strcpy(info->Name, "."); - - dir.dir = p_fs->root_dir; - dir.flags = 0x01; - - if (p_fs->root_dir == CLUSTER_32(0)) { - /* FAT16 root_dir */ - info->Size = p_fs->dentries_in_root << - DENTRY_SIZE_BITS; - } else { - info->Size = count_num_clusters(sb, &dir) << - p_fs->cluster_size_bits; - } - - count = count_dos_name_entries(sb, &dir, TYPE_DIR); - if (count < 0) { - ret = count; /* propagate error upward */ - goto out; - } - info->NumSubdirs = count; - - if (p_fs->dev_ejected) - ret = -EIO; - goto out; - } - } - - /* get the directory entry of given file or directory */ - es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, - ES_2_ENTRIES, &ep); - if (!es) { - ret = -ENOENT; - goto out; - } - ep2 = ep + 1; - - /* set FILE_INFO structure using the acquired struct dentry_t */ - info->Attr = exfat_get_entry_attr(ep); - - exfat_get_entry_time(ep, &tm, TM_CREATE); - info->CreateTimestamp.Year = tm.year; - info->CreateTimestamp.Month = tm.mon; - info->CreateTimestamp.Day = tm.day; - info->CreateTimestamp.Hour = tm.hour; - info->CreateTimestamp.Minute = tm.min; - info->CreateTimestamp.Second = tm.sec; - info->CreateTimestamp.MilliSecond = 0; - - exfat_get_entry_time(ep, &tm, TM_MODIFY); - info->ModifyTimestamp.Year = tm.year; - info->ModifyTimestamp.Month = tm.mon; - info->ModifyTimestamp.Day = tm.day; - info->ModifyTimestamp.Hour = tm.hour; - info->ModifyTimestamp.Minute = tm.min; - info->ModifyTimestamp.Second = tm.sec; - info->ModifyTimestamp.MilliSecond = 0; - - memset((char *)&info->AccessTimestamp, 0, sizeof(struct date_time_t)); - - *uni_name.name = 0x0; - /* XXX this is very bad for exfat cuz name is already included in es. - * API should be revised - */ - exfat_get_uni_name_from_ext_entry(sb, &fid->dir, fid->entry, - uni_name.name); - nls_uniname_to_cstring(sb, info->Name, &uni_name); - - info->NumSubdirs = 2; - - info->Size = exfat_get_entry_size(ep2); - - release_entry_set(es); - - if (is_dir) { - dir.dir = fid->start_clu; - dir.flags = 0x01; - - if (info->Size == 0) - info->Size = (u64)count_num_clusters(sb, &dir) << - p_fs->cluster_size_bits; - - count = count_dos_name_entries(sb, &dir, TYPE_DIR); - if (count < 0) { - ret = count; /* propagate error upward */ - goto out; - } - info->NumSubdirs += count; - } - - if (p_fs->dev_ejected) - ret = -EIO; - -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - pr_debug("%s exited successfully\n", __func__); - return ret; -} - -static int ffsWriteStat(struct inode *inode, struct dir_entry_t *info) -{ - int ret = 0; - struct timestamp_t tm; - struct dentry_t *ep, *ep2; - struct entry_set_cache_t *es = NULL; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct file_id_t *fid = &(EXFAT_I(inode)->fid); - u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; - - pr_debug("%s entered (inode %p info %p\n", __func__, inode, info); - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - if (is_dir) { - if ((fid->dir.dir == p_fs->root_dir) && - (fid->entry == -1)) { - if (p_fs->dev_ejected) - ret = -EIO; - ret = 0; - goto out; - } - } - - fs_set_vol_flags(sb, VOL_DIRTY); - - /* get the directory entry of given file or directory */ - es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, - ES_ALL_ENTRIES, &ep); - if (!es) { - ret = -ENOENT; - goto out; - } - ep2 = ep + 1; - - exfat_set_entry_attr(ep, info->Attr); - - /* set FILE_INFO structure using the acquired struct dentry_t */ - tm.sec = info->CreateTimestamp.Second; - tm.min = info->CreateTimestamp.Minute; - tm.hour = info->CreateTimestamp.Hour; - tm.day = info->CreateTimestamp.Day; - tm.mon = info->CreateTimestamp.Month; - tm.year = info->CreateTimestamp.Year; - exfat_set_entry_time(ep, &tm, TM_CREATE); - - tm.sec = info->ModifyTimestamp.Second; - tm.min = info->ModifyTimestamp.Minute; - tm.hour = info->ModifyTimestamp.Hour; - tm.day = info->ModifyTimestamp.Day; - tm.mon = info->ModifyTimestamp.Month; - tm.year = info->ModifyTimestamp.Year; - exfat_set_entry_time(ep, &tm, TM_MODIFY); - - exfat_set_entry_size(ep2, info->Size); - - update_dir_checksum_with_entry_set(sb, es); - release_entry_set(es); - - if (p_fs->dev_ejected) - ret = -EIO; - -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - pr_debug("%s exited (%d)\n", __func__, ret); - - return ret; -} - -static int ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) -{ - s32 num_clusters, num_alloced; - bool modified = false; - u32 last_clu; - int ret = 0; - struct chain_t new_clu; - struct dentry_t *ep; - struct entry_set_cache_t *es = NULL; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct file_id_t *fid = &(EXFAT_I(inode)->fid); - - /* check the validity of pointer parameters */ - if (!clu) - return -EINVAL; - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - fid->rwoffset = (s64)(clu_offset) << p_fs->cluster_size_bits; - - if (EXFAT_I(inode)->mmu_private == 0) - num_clusters = 0; - else - num_clusters = (s32)((EXFAT_I(inode)->mmu_private - 1) >> - p_fs->cluster_size_bits) + 1; - - *clu = last_clu = fid->start_clu; - - if (fid->flags == 0x03) { - if ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { - last_clu += clu_offset - 1; - - if (clu_offset == num_clusters) - *clu = CLUSTER_32(~0); - else - *clu += clu_offset; - } - } else { - /* hint information */ - if ((clu_offset > 0) && (fid->hint_last_off > 0) && - (clu_offset >= fid->hint_last_off)) { - clu_offset -= fid->hint_last_off; - *clu = fid->hint_last_clu; - } - - while ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { - last_clu = *clu; - if (exfat_fat_read(sb, *clu, clu) == -1) { - ret = -EIO; - goto out; - } - clu_offset--; - } - } - - if (*clu == CLUSTER_32(~0)) { - fs_set_vol_flags(sb, VOL_DIRTY); - - new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : - last_clu + 1; - new_clu.size = 0; - new_clu.flags = fid->flags; - - /* (1) allocate a cluster */ - num_alloced = exfat_alloc_cluster(sb, 1, &new_clu); - if (num_alloced < 0) { - ret = -EIO; - goto out; - } else if (num_alloced == 0) { - ret = -ENOSPC; - goto out; - } - - /* (2) append to the FAT chain */ - if (last_clu == CLUSTER_32(~0)) { - if (new_clu.flags == 0x01) - fid->flags = 0x01; - fid->start_clu = new_clu.dir; - modified = true; - } else { - if (new_clu.flags != fid->flags) { - exfat_chain_cont_cluster(sb, fid->start_clu, - num_clusters); - fid->flags = 0x01; - modified = true; - } - if (new_clu.flags == 0x01) - exfat_fat_write(sb, last_clu, new_clu.dir); - } - - num_clusters += num_alloced; - *clu = new_clu.dir; - - es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, - ES_ALL_ENTRIES, &ep); - if (!es) { - ret = -ENOENT; - goto out; - } - /* get stream entry */ - ep++; - - /* (3) update directory entry */ - if (modified) { - if (exfat_get_entry_flag(ep) != fid->flags) - exfat_set_entry_flag(ep, fid->flags); - - if (exfat_get_entry_clu0(ep) != fid->start_clu) - exfat_set_entry_clu0(ep, fid->start_clu); - } - - update_dir_checksum_with_entry_set(sb, es); - release_entry_set(es); - - /* add number of new blocks to inode */ - inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9); - } - - /* hint information */ - fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); - fid->hint_last_clu = *clu; - - if (p_fs->dev_ejected) - ret = -EIO; - -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} - -/*----------------------------------------------------------------------*/ -/* Directory Operation Functions */ -/*----------------------------------------------------------------------*/ - -static int ffsCreateDir(struct inode *inode, char *path, struct file_id_t *fid) -{ - int ret = 0; - struct chain_t dir; - struct uni_name_t uni_name; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - pr_debug("%s entered\n", __func__); - - /* check the validity of pointer parameters */ - if (!fid || !path || (*path == '\0')) - return -EINVAL; - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - /* check the validity of directory name in the given old pathname */ - ret = resolve_path(inode, path, &dir, &uni_name); - if (ret) - goto out; - - fs_set_vol_flags(sb, VOL_DIRTY); - - ret = create_dir(inode, &dir, &uni_name, fid); - -#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC - fs_sync(sb, true); - fs_set_vol_flags(sb, VOL_CLEAN); -#endif - - if (p_fs->dev_ejected) - ret = -EIO; -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} - -static int ffsReadDir(struct inode *inode, struct dir_entry_t *dir_entry) -{ - int i, dentry, clu_offset; - int ret = 0; - s32 dentries_per_clu, dentries_per_clu_bits = 0; - u32 type; - sector_t sector; - struct chain_t dir, clu; - struct uni_name_t uni_name; - struct timestamp_t tm; - struct dentry_t *ep; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct file_id_t *fid = &(EXFAT_I(inode)->fid); - - /* check the validity of pointer parameters */ - if (!dir_entry) - return -EINVAL; - - /* check if the given file ID is opened */ - if (fid->type != TYPE_DIR) - return -ENOTDIR; - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - if (fid->entry == -1) { - dir.dir = p_fs->root_dir; - dir.flags = 0x01; - } else { - dir.dir = fid->start_clu; - dir.size = (s32)(fid->size >> p_fs->cluster_size_bits); - dir.flags = fid->flags; - } - - dentry = (s32)fid->rwoffset; - - if (dir.dir == CLUSTER_32(0)) { - /* FAT16 root_dir */ - dentries_per_clu = p_fs->dentries_in_root; - - if (dentry == dentries_per_clu) { - clu.dir = CLUSTER_32(~0); - } else { - clu.dir = dir.dir; - clu.size = dir.size; - clu.flags = dir.flags; - } - } else { - dentries_per_clu = p_fs->dentries_per_clu; - dentries_per_clu_bits = ilog2(dentries_per_clu); - - clu_offset = dentry >> dentries_per_clu_bits; - clu.dir = dir.dir; - clu.size = dir.size; - clu.flags = dir.flags; - - if (clu.flags == 0x03) { - clu.dir += clu_offset; - clu.size -= clu_offset; - } else { - /* hint_information */ - if ((clu_offset > 0) && (fid->hint_last_off > 0) && - (clu_offset >= fid->hint_last_off)) { - clu_offset -= fid->hint_last_off; - clu.dir = fid->hint_last_clu; - } - - while (clu_offset > 0) { - /* clu.dir = exfat_fat_read(sb, clu.dir); */ - if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) { - ret = -EIO; - goto out; - } - clu_offset--; - } - } - } - - while (clu.dir != CLUSTER_32(~0)) { - if (p_fs->dev_ejected) - break; - - if (dir.dir == CLUSTER_32(0)) /* FAT16 root_dir */ - i = dentry % dentries_per_clu; - else - i = dentry & (dentries_per_clu - 1); - - for ( ; i < dentries_per_clu; i++, dentry++) { - ep = get_entry_in_dir(sb, &clu, i, §or); - if (!ep) { - ret = -ENOENT; - goto out; - } - type = exfat_get_entry_type(ep); - - if (type == TYPE_UNUSED) - break; - - if ((type != TYPE_FILE) && (type != TYPE_DIR)) - continue; - - exfat_buf_lock(sb, sector); - dir_entry->Attr = exfat_get_entry_attr(ep); - - exfat_get_entry_time(ep, &tm, TM_CREATE); - dir_entry->CreateTimestamp.Year = tm.year; - dir_entry->CreateTimestamp.Month = tm.mon; - dir_entry->CreateTimestamp.Day = tm.day; - dir_entry->CreateTimestamp.Hour = tm.hour; - dir_entry->CreateTimestamp.Minute = tm.min; - dir_entry->CreateTimestamp.Second = tm.sec; - dir_entry->CreateTimestamp.MilliSecond = 0; - - exfat_get_entry_time(ep, &tm, TM_MODIFY); - dir_entry->ModifyTimestamp.Year = tm.year; - dir_entry->ModifyTimestamp.Month = tm.mon; - dir_entry->ModifyTimestamp.Day = tm.day; - dir_entry->ModifyTimestamp.Hour = tm.hour; - dir_entry->ModifyTimestamp.Minute = tm.min; - dir_entry->ModifyTimestamp.Second = tm.sec; - dir_entry->ModifyTimestamp.MilliSecond = 0; - - memset((char *)&dir_entry->AccessTimestamp, 0, - sizeof(struct date_time_t)); - - *uni_name.name = 0x0; - exfat_get_uni_name_from_ext_entry(sb, &dir, dentry, - uni_name.name); - nls_uniname_to_cstring(sb, dir_entry->Name, &uni_name); - exfat_buf_unlock(sb, sector); - - ep = get_entry_in_dir(sb, &clu, i + 1, NULL); - if (!ep) { - ret = -ENOENT; - goto out; - } - - dir_entry->Size = exfat_get_entry_size(ep); - - /* hint information */ - if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */ - } else { - fid->hint_last_off = dentry >> - dentries_per_clu_bits; - fid->hint_last_clu = clu.dir; - } - - fid->rwoffset = (s64)(++dentry); - - if (p_fs->dev_ejected) - ret = -EIO; - goto out; - } - - if (dir.dir == CLUSTER_32(0)) - break; /* FAT16 root_dir */ - - if (clu.flags == 0x03) { - if ((--clu.size) > 0) - clu.dir++; - else - clu.dir = CLUSTER_32(~0); - } else { - /* clu.dir = exfat_fat_read(sb, clu.dir); */ - if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) { - ret = -EIO; - goto out; - } - } - } - - *dir_entry->Name = '\0'; - - fid->rwoffset = (s64)(++dentry); - - if (p_fs->dev_ejected) - ret = -EIO; - -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} - -static int ffsRemoveDir(struct inode *inode, struct file_id_t *fid) -{ - s32 dentry; - int ret = 0; - struct chain_t dir, clu_to_free; - struct super_block *sb = inode->i_sb; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - /* check the validity of the given file id */ - if (!fid) - return -EINVAL; - - dir.dir = fid->dir.dir; - dir.size = fid->dir.size; - dir.flags = fid->dir.flags; - - dentry = fid->entry; - - /* check if the file is "." or ".." */ - if (p_fs->vol_type != EXFAT) { - if ((dir.dir != p_fs->root_dir) && (dentry < 2)) - return -EPERM; - } - - /* acquire the lock for file system critical section */ - mutex_lock(&p_fs->v_mutex); - - clu_to_free.dir = fid->start_clu; - clu_to_free.size = (s32)((fid->size - 1) >> p_fs->cluster_size_bits) + 1; - clu_to_free.flags = fid->flags; - - if (!is_dir_empty(sb, &clu_to_free)) { - ret = -ENOTEMPTY; - goto out; - } - - fs_set_vol_flags(sb, VOL_DIRTY); - - /* (1) update the directory entry */ - remove_file(inode, &dir, dentry); - - /* (2) free the clusters */ - exfat_free_cluster(sb, &clu_to_free, 1); - - fid->size = 0; - fid->start_clu = CLUSTER_32(~0); - fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; - -#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC - fs_sync(sb, true); - fs_set_vol_flags(sb, VOL_CLEAN); -#endif - - if (p_fs->dev_ejected) - ret = -EIO; - -out: - /* release the lock for file system critical section */ - mutex_unlock(&p_fs->v_mutex); - - return ret; -} - -/*======================================================================*/ -/* Directory Entry Operations */ -/*======================================================================*/ - -static int exfat_readdir(struct file *filp, struct dir_context *ctx) -{ - struct inode *inode = file_inode(filp); - struct super_block *sb = inode->i_sb; - struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct fs_info_t *p_fs = &sbi->fs_info; - struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - struct dir_entry_t de; - unsigned long inum; - loff_t cpos; - int err = 0; - - __lock_super(sb); - - cpos = ctx->pos; - /* Fake . and .. for the root directory. */ - if ((p_fs->vol_type == EXFAT) || (inode->i_ino == EXFAT_ROOT_INO)) { - while (cpos < 2) { - if (inode->i_ino == EXFAT_ROOT_INO) - inum = EXFAT_ROOT_INO; - else if (cpos == 0) - inum = inode->i_ino; - else /* (cpos == 1) */ - inum = parent_ino(filp->f_path.dentry); - - if (!dir_emit_dots(filp, ctx)) - goto out; - cpos++; - ctx->pos++; - } - if (cpos == 2) - cpos = 0; - } - if (cpos & (DENTRY_SIZE - 1)) { - err = -ENOENT; - goto out; - } - -get_new: - EXFAT_I(inode)->fid.size = i_size_read(inode); - EXFAT_I(inode)->fid.rwoffset = cpos >> DENTRY_SIZE_BITS; - - err = ffsReadDir(inode, &de); - if (err) { - /* at least we tried to read a sector - * move cpos to next sector position (should be aligned) - */ - if (err == -EIO) { - cpos += 1 << p_bd->sector_size_bits; - cpos &= ~((1 << p_bd->sector_size_bits) - 1); - } - - goto end_of_dir; - } - - cpos = EXFAT_I(inode)->fid.rwoffset << DENTRY_SIZE_BITS; - - if (!de.Name[0]) - goto end_of_dir; - - if (!memcmp(de.ShortName, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH)) { - inum = inode->i_ino; - } else if (!memcmp(de.ShortName, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH)) { - inum = parent_ino(filp->f_path.dentry); - } else { - loff_t i_pos = ((loff_t)EXFAT_I(inode)->fid.start_clu << 32) | - ((EXFAT_I(inode)->fid.rwoffset - 1) & 0xffffffff); - struct inode *tmp = exfat_iget(sb, i_pos); - - if (tmp) { - inum = tmp->i_ino; - iput(tmp); - } else { - inum = iunique(sb, EXFAT_ROOT_INO); - } - } - - if (!dir_emit(ctx, de.Name, strlen(de.Name), inum, - (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) - goto out; - - ctx->pos = cpos; - goto get_new; - -end_of_dir: - ctx->pos = cpos; -out: - __unlock_super(sb); - return err; -} - -static int exfat_ioctl_volume_id(struct inode *dir) -{ - struct super_block *sb = dir->i_sb; - struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct fs_info_t *p_fs = &sbi->fs_info; - - return p_fs->vol_id; -} - -static long exfat_generic_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct inode *inode = filp->f_path.dentry->d_inode; -#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG - unsigned int flags; -#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ - - switch (cmd) { - case EXFAT_IOCTL_GET_VOLUME_ID: - return exfat_ioctl_volume_id(inode); -#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG - case EXFAT_IOC_GET_DEBUGFLAGS: { - struct super_block *sb = inode->i_sb; - struct exfat_sb_info *sbi = EXFAT_SB(sb); - - flags = sbi->debug_flags; - return put_user(flags, (int __user *)arg); - } - case EXFAT_IOC_SET_DEBUGFLAGS: { - struct super_block *sb = inode->i_sb; - struct exfat_sb_info *sbi = EXFAT_SB(sb); - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (get_user(flags, (int __user *)arg)) - return -EFAULT; - - __lock_super(sb); - sbi->debug_flags = flags; - __unlock_super(sb); - - return 0; - } -#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ - default: - return -ENOTTY; /* Inappropriate ioctl for device */ - } -} - -static const struct file_operations exfat_dir_operations = { - .llseek = generic_file_llseek, - .read = generic_read_dir, - .iterate = exfat_readdir, - .unlocked_ioctl = exfat_generic_ioctl, - .fsync = generic_file_fsync, -}; - -static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, - bool excl) -{ - struct super_block *sb = dir->i_sb; - struct timespec64 curtime; - struct inode *inode; - struct file_id_t fid; - loff_t i_pos; - int err; - - __lock_super(sb); - - pr_debug("%s entered\n", __func__); - - err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_REGULAR, &fid); - if (err) - goto out; - - INC_IVERSION(dir); - curtime = current_time(dir); - dir->i_ctime = curtime; - dir->i_mtime = curtime; - dir->i_atime = curtime; - if (IS_DIRSYNC(dir)) - (void)exfat_sync_inode(dir); - else - mark_inode_dirty(dir); - - i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff); - - inode = exfat_build_inode(sb, &fid, i_pos); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto out; - } - INC_IVERSION(inode); - curtime = current_time(inode); - inode->i_mtime = curtime; - inode->i_atime = curtime; - inode->i_ctime = curtime; - /* - * timestamp is already written, so mark_inode_dirty() is unnecessary. - */ - - dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); - d_instantiate(dentry, inode); - -out: - __unlock_super(sb); - pr_debug("%s exited\n", __func__); - return err; -} - -static int exfat_find(struct inode *dir, struct qstr *qname, - struct file_id_t *fid) -{ - int err; - - if (qname->len == 0) - return -ENOENT; - - err = ffsLookupFile(dir, (u8 *)qname->name, fid); - if (err) - return -ENOENT; - - return 0; -} - -static int exfat_d_anon_disconn(struct dentry *dentry) -{ - return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); -} - -static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, - unsigned int flags) -{ - struct super_block *sb = dir->i_sb; - struct inode *inode; - struct dentry *alias; - int err; - struct file_id_t fid; - loff_t i_pos; - u64 ret; - mode_t i_mode; - - __lock_super(sb); - pr_debug("%s entered\n", __func__); - err = exfat_find(dir, &dentry->d_name, &fid); - if (err) { - if (err == -ENOENT) { - inode = NULL; - goto out; - } - goto error; - } - - i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff); - inode = exfat_build_inode(sb, &fid, i_pos); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto error; - } - - i_mode = inode->i_mode; - if (S_ISLNK(i_mode) && !EXFAT_I(inode)->target) { - EXFAT_I(inode)->target = kmalloc(i_size_read(inode) + 1, - GFP_KERNEL); - if (!EXFAT_I(inode)->target) { - err = -ENOMEM; - goto error; - } - ffsReadFile(dir, &fid, EXFAT_I(inode)->target, - i_size_read(inode), &ret); - *(EXFAT_I(inode)->target + i_size_read(inode)) = '\0'; - } - - alias = d_find_alias(inode); - if (alias && !exfat_d_anon_disconn(alias)) { - BUG_ON(d_unhashed(alias)); - if (!S_ISDIR(i_mode)) - d_move(alias, dentry); - iput(inode); - __unlock_super(sb); - pr_debug("%s exited 1\n", __func__); - return alias; - } - dput(alias); -out: - __unlock_super(sb); - dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); - dentry = d_splice_alias(inode, dentry); - if (dentry) - dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); - pr_debug("%s exited 2\n", __func__); - return dentry; - -error: - __unlock_super(sb); - pr_debug("%s exited 3\n", __func__); - return ERR_PTR(err); -} - -static inline unsigned long exfat_hash(loff_t i_pos) -{ - return hash_32(i_pos, EXFAT_HASH_BITS); -} - -static void exfat_attach(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); -} - -static void exfat_detach(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); -} - -static int exfat_unlink(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - struct super_block *sb = dir->i_sb; - struct timespec64 curtime; - int err; - - __lock_super(sb); - - pr_debug("%s entered\n", __func__); - - EXFAT_I(inode)->fid.size = i_size_read(inode); - - err = ffsRemoveFile(dir, &(EXFAT_I(inode)->fid)); - if (err) - goto out; - - INC_IVERSION(dir); - curtime = current_time(dir); - dir->i_mtime = curtime; - dir->i_atime = curtime; - if (IS_DIRSYNC(dir)) - (void)exfat_sync_inode(dir); - else - mark_inode_dirty(dir); - - clear_nlink(inode); - curtime = current_time(inode); - inode->i_mtime = curtime; - inode->i_atime = curtime; - exfat_detach(inode); - remove_inode_hash(inode); - -out: - __unlock_super(sb); - pr_debug("%s exited\n", __func__); - return err; -} - -static int exfat_symlink(struct inode *dir, struct dentry *dentry, - const char *target) -{ - struct super_block *sb = dir->i_sb; - struct timespec64 curtime; - struct inode *inode; - struct file_id_t fid; - loff_t i_pos; - int err; - u64 len = (u64)strlen(target); - u64 ret; - - __lock_super(sb); - - pr_debug("%s entered\n", __func__); - - err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_SYMLINK, &fid); - if (err) - goto out; - - - err = ffsWriteFile(dir, &fid, (char *)target, len, &ret); - - if (err) { - ffsRemoveFile(dir, &fid); - goto out; - } - - INC_IVERSION(dir); - curtime = current_time(dir); - dir->i_ctime = curtime; - dir->i_mtime = curtime; - dir->i_atime = curtime; - if (IS_DIRSYNC(dir)) - (void)exfat_sync_inode(dir); - else - mark_inode_dirty(dir); - - i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff); - - inode = exfat_build_inode(sb, &fid, i_pos); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto out; - } - INC_IVERSION(inode); - curtime = current_time(inode); - inode->i_mtime = curtime; - inode->i_atime = curtime; - inode->i_ctime = curtime; - /* timestamp is already written, so mark_inode_dirty() is unneeded. */ - - EXFAT_I(inode)->target = kmemdup(target, len + 1, GFP_KERNEL); - if (!EXFAT_I(inode)->target) { - err = -ENOMEM; - goto out; - } - - dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); - d_instantiate(dentry, inode); - -out: - __unlock_super(sb); - pr_debug("%s exited\n", __func__); - return err; -} - -static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - struct super_block *sb = dir->i_sb; - struct timespec64 curtime; - struct inode *inode; - struct file_id_t fid; - loff_t i_pos; - int err; - - __lock_super(sb); - - pr_debug("%s entered\n", __func__); - - err = ffsCreateDir(dir, (u8 *)dentry->d_name.name, &fid); - if (err) - goto out; - - INC_IVERSION(dir); - curtime = current_time(dir); - dir->i_ctime = curtime; - dir->i_mtime = curtime; - dir->i_atime = curtime; - if (IS_DIRSYNC(dir)) - (void)exfat_sync_inode(dir); - else - mark_inode_dirty(dir); - inc_nlink(dir); - - i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff); - - inode = exfat_build_inode(sb, &fid, i_pos); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto out; - } - INC_IVERSION(inode); - curtime = current_time(inode); - inode->i_mtime = curtime; - inode->i_atime = curtime; - inode->i_ctime = curtime; - /* timestamp is already written, so mark_inode_dirty() is unneeded. */ - - dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); - d_instantiate(dentry, inode); - -out: - __unlock_super(sb); - pr_debug("%s exited\n", __func__); - return err; -} - -static int exfat_rmdir(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - struct super_block *sb = dir->i_sb; - struct timespec64 curtime; - int err; - - __lock_super(sb); - - pr_debug("%s entered\n", __func__); - - EXFAT_I(inode)->fid.size = i_size_read(inode); - - err = ffsRemoveDir(dir, &(EXFAT_I(inode)->fid)); - if (err) - goto out; - - INC_IVERSION(dir); - curtime = current_time(dir); - dir->i_mtime = curtime; - dir->i_atime = curtime; - if (IS_DIRSYNC(dir)) - (void)exfat_sync_inode(dir); - else - mark_inode_dirty(dir); - drop_nlink(dir); - - clear_nlink(inode); - curtime = current_time(inode); - inode->i_mtime = curtime; - inode->i_atime = curtime; - exfat_detach(inode); - remove_inode_hash(inode); - -out: - __unlock_super(sb); - pr_debug("%s exited\n", __func__); - return err; -} - -static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) -{ - struct inode *old_inode, *new_inode; - struct super_block *sb = old_dir->i_sb; - struct timespec64 curtime; - loff_t i_pos; - int err; - - if (flags) - return -EINVAL; - - __lock_super(sb); - - pr_debug("%s entered\n", __func__); - - old_inode = old_dentry->d_inode; - new_inode = new_dentry->d_inode; - - EXFAT_I(old_inode)->fid.size = i_size_read(old_inode); - - err = ffsMoveFile(old_dir, &(EXFAT_I(old_inode)->fid), new_dir, - new_dentry); - if (err) - goto out; - - INC_IVERSION(new_dir); - curtime = current_time(new_dir); - new_dir->i_ctime = curtime; - new_dir->i_mtime = curtime; - new_dir->i_atime = curtime; - - if (IS_DIRSYNC(new_dir)) - (void)exfat_sync_inode(new_dir); - else - mark_inode_dirty(new_dir); - - i_pos = ((loff_t)EXFAT_I(old_inode)->fid.dir.dir << 32) | - (EXFAT_I(old_inode)->fid.entry & 0xffffffff); - - exfat_detach(old_inode); - exfat_attach(old_inode, i_pos); - if (IS_DIRSYNC(new_dir)) - (void)exfat_sync_inode(old_inode); - else - mark_inode_dirty(old_inode); - - if ((S_ISDIR(old_inode->i_mode)) && (old_dir != new_dir)) { - drop_nlink(old_dir); - if (!new_inode) - inc_nlink(new_dir); - } - INC_IVERSION(old_dir); - curtime = current_time(old_dir); - old_dir->i_ctime = curtime; - old_dir->i_mtime = curtime; - if (IS_DIRSYNC(old_dir)) - (void)exfat_sync_inode(old_dir); - else - mark_inode_dirty(old_dir); - - if (new_inode) { - exfat_detach(new_inode); - drop_nlink(new_inode); - if (S_ISDIR(new_inode->i_mode)) - drop_nlink(new_inode); - new_inode->i_ctime = current_time(new_inode); - } - -out: - __unlock_super(sb); - pr_debug("%s exited\n", __func__); - return err; -} - -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); - struct timespec64 curtime; - int err, err2; - - err = generic_cont_expand_simple(inode, size); - if (err != 0) - return err; - - curtime = current_time(inode); - inode->i_ctime = curtime; - inode->i_mtime = curtime; - mark_inode_dirty(inode); - - if (IS_SYNC(inode)) { - err = filemap_fdatawrite_range(mapping, start, - start + count - 1); - err2 = sync_mapping_buffers(mapping); - err = (err) ? (err) : (err2); - err2 = write_inode_now(inode, 1); - err = (err) ? (err) : (err2); - if (!err) - err = filemap_fdatawait_range(mapping, start, - start + count - 1); - } - return err; -} - -static int 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 1; - } - - /* use a default check */ - return 0; -} - -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; - - if (S_ISREG(i_mode) || S_ISLNK(i_mode)) - mask = sbi->options.fs_fmask; - else - mask = 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; -} - -static void exfat_truncate(struct inode *inode, loff_t old_size) -{ - struct super_block *sb = inode->i_sb; - struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct fs_info_t *p_fs = &sbi->fs_info; - struct timespec64 curtime; - int err; - - __lock_super(sb); - - /* - * This protects against truncating a file bigger than it was then - * trying to write into the hole. - */ - if (EXFAT_I(inode)->mmu_private > i_size_read(inode)) - EXFAT_I(inode)->mmu_private = i_size_read(inode); - - if (EXFAT_I(inode)->fid.start_clu == 0) - goto out; - - err = ffsTruncateFile(inode, old_size, i_size_read(inode)); - if (err) - goto out; - - curtime = current_time(inode); - inode->i_ctime = curtime; - inode->i_mtime = curtime; - if (IS_DIRSYNC(inode)) - (void)exfat_sync_inode(inode); - else - mark_inode_dirty(inode); - - inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) & - ~((loff_t)p_fs->cluster_size - 1)) >> 9; -out: - __unlock_super(sb); -} - -static 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; - loff_t old_size; - - pr_debug("%s entered\n", __func__); - - 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) - return error; - attr->ia_valid &= ~ATTR_SIZE; - } - - 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) - return error; - - 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)))) { - return -EPERM; - } - - /* - * 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; - } - - EXFAT_I(inode)->fid.size = i_size_read(inode); - - if (attr->ia_valid & ATTR_SIZE) { - old_size = i_size_read(inode); - down_write(&EXFAT_I(inode)->truncate_lock); - truncate_setsize(inode, attr->ia_size); - exfat_truncate(inode, old_size); - up_write(&EXFAT_I(inode)->truncate_lock); - } - setattr_copy(inode, attr); - mark_inode_dirty(inode); - - pr_debug("%s exited\n", __func__); - return error; -} - -static int exfat_getattr(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int flags) -{ - struct inode *inode = path->dentry->d_inode; - - pr_debug("%s entered\n", __func__); - - generic_fillattr(inode, stat); - stat->blksize = EXFAT_SB(inode->i_sb)->fs_info.cluster_size; - - pr_debug("%s exited\n", __func__); - return 0; -} - -static const struct inode_operations exfat_dir_inode_operations = { - .create = exfat_create, - .lookup = exfat_lookup, - .unlink = exfat_unlink, - .symlink = exfat_symlink, - .mkdir = exfat_mkdir, - .rmdir = exfat_rmdir, - .rename = exfat_rename, - .setattr = exfat_setattr, - .getattr = exfat_getattr, -}; - -/*======================================================================*/ -/* File Operations */ -/*======================================================================*/ -static const char *exfat_get_link(struct dentry *dentry, struct inode *inode, - struct delayed_call *done) -{ - struct exfat_inode_info *ei = EXFAT_I(inode); - - if (ei->target) { - char *cookie = ei->target; - - if (cookie) - return (char *)(ei->target); - } - return NULL; -} - -static const struct inode_operations exfat_symlink_inode_operations = { - .get_link = exfat_get_link, -}; - -static int exfat_file_release(struct inode *inode, struct file *filp) -{ - struct super_block *sb = inode->i_sb; - - EXFAT_I(inode)->fid.size = i_size_read(inode); - ffsSyncVol(sb, false); - return 0; -} - -static 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, - .release = exfat_file_release, - .unlocked_ioctl = exfat_generic_ioctl, - .fsync = generic_file_fsync, - .splice_read = generic_file_splice_read, -}; - -static const struct inode_operations exfat_file_inode_operations = { - .setattr = exfat_setattr, - .getattr = exfat_getattr, -}; - -/*======================================================================*/ -/* Address Space Operations */ -/*======================================================================*/ - -static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, - unsigned long *mapped_blocks, int *create) -{ - struct super_block *sb = inode->i_sb; - struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct fs_info_t *p_fs = &sbi->fs_info; - const unsigned long blocksize = sb->s_blocksize; - const unsigned char blocksize_bits = sb->s_blocksize_bits; - sector_t last_block; - int err, clu_offset, sec_offset; - unsigned int cluster; - - *phys = 0; - *mapped_blocks = 0; - - last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; - if (sector >= last_block) { - if (*create == 0) - return 0; - } else { - *create = 0; - } - - /* cluster offset */ - clu_offset = sector >> p_fs->sectors_per_clu_bits; - - /* sector offset in cluster */ - sec_offset = sector & (p_fs->sectors_per_clu - 1); - - EXFAT_I(inode)->fid.size = i_size_read(inode); - - err = ffsMapCluster(inode, clu_offset, &cluster); - - if (!err && (cluster != CLUSTER_32(~0))) { - *phys = START_SECTOR(cluster) + sec_offset; - *mapped_blocks = p_fs->sectors_per_clu - sec_offset; - } - - return 0; -} - -static int exfat_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create) -{ - struct super_block *sb = inode->i_sb; - unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; - int err; - unsigned long mapped_blocks; - sector_t phys; - - __lock_super(sb); - - err = exfat_bmap(inode, iblock, &phys, &mapped_blocks, &create); - if (err) { - __unlock_super(sb); - return err; - } - - if (phys) { - max_blocks = min(mapped_blocks, max_blocks); - if (create) { - EXFAT_I(inode)->mmu_private += max_blocks << - sb->s_blocksize_bits; - set_buffer_new(bh_result); - } - map_bh(bh_result, sb, phys); - } - - bh_result->b_size = max_blocks << sb->s_blocksize_bits; - __unlock_super(sb); - - return 0; -} - -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_I(inode)->fid.size = i_size_read(inode); - exfat_truncate(inode, i_size_read(inode)); - } -} - -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)->mmu_private); - - 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 file_id_t *fid = &(EXFAT_I(inode)->fid); - struct timespec64 curtime; - int err; - - err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); - - if (err < len) - exfat_write_failed(mapping, pos + len); - - if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { - curtime = current_time(inode); - inode->i_mtime = curtime; - inode->i_ctime = curtime; - fid->attr |= ATTR_ARCHIVE; - mark_inode_dirty(inode); - } - return err; -} - -static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) -{ - struct inode *inode = iocb->ki_filp->f_mapping->host; - struct address_space *mapping = iocb->ki_filp->f_mapping; - ssize_t ret; - int rw; - - rw = iov_iter_rw(iter); - - if (rw == WRITE) { - if (EXFAT_I(inode)->mmu_private < iov_iter_count(iter)) - return 0; - } - ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); - - if ((ret < 0) && (rw & WRITE)) - exfat_write_failed(mapping, iov_iter_count(iter)); - return ret; -} - -static sector_t _exfat_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; -} - -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_bmap -}; - -/*======================================================================*/ -/* Super Operations */ -/*======================================================================*/ - -static 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) { - BUG_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 file_id_t *fid) -{ - struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); - struct fs_info_t *p_fs = &sbi->fs_info; - struct dir_entry_t info; - - memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(struct file_id_t)); - - ffsReadStat(inode, &info); - - EXFAT_I(inode)->i_pos = 0; - EXFAT_I(inode)->target = NULL; - inode->i_uid = sbi->options.fs_uid; - inode->i_gid = sbi->options.fs_gid; - 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; - - i_size_write(inode, info.Size); - EXFAT_I(inode)->mmu_private = i_size_read(inode); - set_nlink(inode, info.NumSubdirs); - } else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */ - inode->i_generation |= 1; - inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777); - inode->i_op = &exfat_symlink_inode_operations; - - i_size_write(inode, info.Size); - EXFAT_I(inode)->mmu_private = i_size_read(inode); - } 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, info.Size); - EXFAT_I(inode)->mmu_private = i_size_read(inode); - } - exfat_save_attr(inode, info.Attr); - - inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) - & ~((loff_t)p_fs->cluster_size - 1)) >> 9; - - exfat_time_fat2unix(&inode->i_mtime, &info.ModifyTimestamp); - exfat_time_fat2unix(&inode->i_ctime, &info.CreateTimestamp); - exfat_time_fat2unix(&inode->i_atime, &info.AccessTimestamp); - - return 0; -} - -static struct inode *exfat_build_inode(struct super_block *sb, - struct file_id_t *fid, 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); - SET_IVERSION(inode, 1); - err = exfat_fill_inode(inode, fid); - if (err) { - iput(inode); - inode = ERR_PTR(err); - goto out; - } - exfat_attach(inode, i_pos); - insert_inode_hash(inode); -out: - return inode; -} - -static int exfat_sync_inode(struct inode *inode) -{ - return exfat_write_inode(inode, NULL); -} - -static struct inode *exfat_alloc_inode(struct super_block *sb) -{ - struct exfat_inode_info *ei; - - ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS); - if (!ei) - return NULL; - - init_rwsem(&ei->truncate_lock); - - return &ei->vfs_inode; -} - -static void exfat_destroy_inode(struct inode *inode) -{ - kfree(EXFAT_I(inode)->target); - EXFAT_I(inode)->target = NULL; - - kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); -} - -static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) -{ - struct dir_entry_t info; - - if (inode->i_ino == EXFAT_ROOT_INO) - return 0; - - info.Attr = exfat_make_attr(inode); - info.Size = i_size_read(inode); - - exfat_time_unix2fat(&inode->i_mtime, &info.ModifyTimestamp); - exfat_time_unix2fat(&inode->i_ctime, &info.CreateTimestamp); - exfat_time_unix2fat(&inode->i_atime, &info.AccessTimestamp); - - ffsWriteStat(inode, &info); - - return 0; -} - -static void exfat_evict_inode(struct inode *inode) -{ - truncate_inode_pages(&inode->i_data, 0); - - if (!inode->i_nlink) - i_size_write(inode, 0); - invalidate_inode_buffers(inode); - clear_inode(inode); - exfat_detach(inode); - - remove_inode_hash(inode); -} - -static void exfat_free_super(struct exfat_sb_info *sbi) -{ - if (sbi->nls_disk) - unload_nls(sbi->nls_disk); - if (sbi->nls_io) - unload_nls(sbi->nls_io); - if (sbi->options.iocharset != exfat_default_iocharset) - kfree(sbi->options.iocharset); - /* mutex_init is in exfat_fill_super function. only for 3.7+ */ - mutex_destroy(&sbi->s_lock); - kvfree(sbi); -} - -static void exfat_put_super(struct super_block *sb) -{ - struct exfat_sb_info *sbi = EXFAT_SB(sb); - - if (__is_sb_dirty(sb)) - exfat_write_super(sb); - - ffsUmountVol(sb); - - sb->s_fs_info = NULL; - exfat_free_super(sbi); -} - -static void exfat_write_super(struct super_block *sb) -{ - __lock_super(sb); - - __set_sb_clean(sb); - - if (!sb_rdonly(sb)) - ffsSyncVol(sb, true); - - __unlock_super(sb); -} - -static int exfat_sync_fs(struct super_block *sb, int wait) -{ - int err = 0; - - if (__is_sb_dirty(sb)) { - __lock_super(sb); - __set_sb_clean(sb); - err = ffsSyncVol(sb, true); - __unlock_super(sb); - } - - return err; -} - -static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) -{ - struct super_block *sb = dentry->d_sb; - u64 id = huge_encode_dev(sb->s_bdev->bd_dev); - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - struct vol_info_t info; - - if (p_fs->used_clusters == UINT_MAX) { - if (ffsGetVolInfo(sb, &info) == -EIO) - return -EIO; - - } else { - info.FatType = p_fs->vol_type; - info.ClusterSize = p_fs->cluster_size; - info.NumClusters = p_fs->num_clusters - 2; - info.UsedClusters = p_fs->used_clusters; - info.FreeClusters = info.NumClusters - info.UsedClusters; - - if (p_fs->dev_ejected) - pr_info("[EXFAT] statfs on device that is ejected\n"); - } - - buf->f_type = sb->s_magic; - buf->f_bsize = info.ClusterSize; - buf->f_blocks = info.NumClusters; - buf->f_bfree = info.FreeClusters; - buf->f_bavail = info.FreeClusters; - buf->f_fsid.val[0] = (u32)id; - buf->f_fsid.val[1] = (u32)(id >> 32); - buf->f_namelen = 260; - - return 0; -} - -static int exfat_remount(struct super_block *sb, int *flags, char *data) -{ - *flags |= SB_NODIRATIME; - return 0; -} - -static int exfat_show_options(struct seq_file *m, struct dentry *root) -{ - struct exfat_sb_info *sbi = EXFAT_SB(root->d_sb); - struct exfat_mount_options *opts = &sbi->options; - - if (__kuid_val(opts->fs_uid)) - seq_printf(m, ",uid=%u", __kuid_val(opts->fs_uid)); - if (__kgid_val(opts->fs_gid)) - seq_printf(m, ",gid=%u", __kgid_val(opts->fs_gid)); - seq_printf(m, ",fmask=%04o", opts->fs_fmask); - seq_printf(m, ",dmask=%04o", opts->fs_dmask); - if (opts->allow_utime) - seq_printf(m, ",allow_utime=%04o", opts->allow_utime); - if (sbi->nls_disk) - seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); - if (sbi->nls_io) - seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); - seq_printf(m, ",namecase=%u", opts->casesensitive); - if (opts->errors == EXFAT_ERRORS_CONT) - seq_puts(m, ",errors=continue"); - else if (opts->errors == EXFAT_ERRORS_PANIC) - seq_puts(m, ",errors=panic"); - else - seq_puts(m, ",errors=remount-ro"); -#ifdef CONFIG_STAGING_EXFAT_DISCARD - if (opts->discard) - seq_puts(m, ",discard"); -#endif - return 0; -} - -static const struct super_operations exfat_sops = { - .alloc_inode = exfat_alloc_inode, - .destroy_inode = exfat_destroy_inode, - .write_inode = exfat_write_inode, - .evict_inode = exfat_evict_inode, - .put_super = exfat_put_super, - .sync_fs = exfat_sync_fs, - .statfs = exfat_statfs, - .remount_fs = exfat_remount, - .show_options = exfat_show_options, -}; - -/*======================================================================*/ -/* Export Operations */ -/*======================================================================*/ - -static struct inode *exfat_nfs_get_inode(struct super_block *sb, u64 ino, - u32 generation) -{ - struct inode *inode = NULL; - - if (ino < EXFAT_ROOT_INO) - return inode; - inode = ilookup(sb, ino); - - if (inode && generation && (inode->i_generation != generation)) { - iput(inode); - inode = NULL; - } - - return inode; -} - -static struct dentry *exfat_fh_to_dentry(struct super_block *sb, - struct fid *fid, int fh_len, - int fh_type) -{ - return generic_fh_to_dentry(sb, fid, fh_len, fh_type, - exfat_nfs_get_inode); -} - -static struct dentry *exfat_fh_to_parent(struct super_block *sb, - struct fid *fid, int fh_len, - int fh_type) -{ - return generic_fh_to_parent(sb, fid, fh_len, fh_type, - exfat_nfs_get_inode); -} - -static const struct export_operations exfat_export_ops = { - .fh_to_dentry = exfat_fh_to_dentry, - .fh_to_parent = exfat_fh_to_parent, -}; - -/*======================================================================*/ -/* Super Block Read Operations */ -/*======================================================================*/ - -enum { - Opt_uid, - Opt_gid, - Opt_umask, - Opt_dmask, - Opt_fmask, - Opt_allow_utime, - Opt_codepage, - Opt_charset, - Opt_namecase, - Opt_debug, - Opt_err_cont, - Opt_err_panic, - Opt_err_ro, - Opt_utf8_hack, - Opt_err, -#ifdef CONFIG_STAGING_EXFAT_DISCARD - Opt_discard, -#endif /* EXFAT_CONFIG_DISCARD */ -}; - -static const match_table_t exfat_tokens = { - {Opt_uid, "uid=%u"}, - {Opt_gid, "gid=%u"}, - {Opt_umask, "umask=%o"}, - {Opt_dmask, "dmask=%o"}, - {Opt_fmask, "fmask=%o"}, - {Opt_allow_utime, "allow_utime=%o"}, - {Opt_codepage, "codepage=%u"}, - {Opt_charset, "iocharset=%s"}, - {Opt_namecase, "namecase=%u"}, - {Opt_debug, "debug"}, - {Opt_err_cont, "errors=continue"}, - {Opt_err_panic, "errors=panic"}, - {Opt_err_ro, "errors=remount-ro"}, - {Opt_utf8_hack, "utf8"}, -#ifdef CONFIG_STAGING_EXFAT_DISCARD - {Opt_discard, "discard"}, -#endif /* CONFIG_STAGING_EXFAT_DISCARD */ - {Opt_err, NULL} -}; - -static int parse_options(char *options, int silent, int *debug, - struct exfat_mount_options *opts) -{ - char *p; - substring_t args[MAX_OPT_ARGS]; - int option; - char *iocharset; - - opts->fs_uid = current_uid(); - opts->fs_gid = current_gid(); - opts->fs_fmask = current->fs->umask; - opts->fs_dmask = current->fs->umask; - opts->allow_utime = U16_MAX; - opts->codepage = exfat_default_codepage; - opts->iocharset = exfat_default_iocharset; - opts->casesensitive = 0; - opts->errors = EXFAT_ERRORS_RO; -#ifdef CONFIG_STAGING_EXFAT_DISCARD - opts->discard = 0; -#endif - *debug = 0; - - if (!options) - goto out; - - while ((p = strsep(&options, ","))) { - int token; - - if (!*p) - continue; - - token = match_token(p, exfat_tokens, args); - switch (token) { - case Opt_uid: - if (match_int(&args[0], &option)) - return 0; - opts->fs_uid = KUIDT_INIT(option); - break; - case Opt_gid: - if (match_int(&args[0], &option)) - return 0; - opts->fs_gid = KGIDT_INIT(option); - break; - case Opt_umask: - case Opt_dmask: - case Opt_fmask: - if (match_octal(&args[0], &option)) - return 0; - if (token != Opt_dmask) - opts->fs_fmask = option; - if (token != Opt_fmask) - opts->fs_dmask = option; - break; - case Opt_allow_utime: - if (match_octal(&args[0], &option)) - return 0; - opts->allow_utime = option & 0022; - break; - case Opt_codepage: - if (match_int(&args[0], &option)) - return 0; - opts->codepage = option; - break; - case Opt_charset: - if (opts->iocharset != exfat_default_iocharset) - kfree(opts->iocharset); - iocharset = match_strdup(&args[0]); - if (!iocharset) - return -ENOMEM; - opts->iocharset = iocharset; - break; - case Opt_namecase: - if (match_int(&args[0], &option)) - return 0; - opts->casesensitive = option; - break; - case Opt_err_cont: - opts->errors = EXFAT_ERRORS_CONT; - break; - case Opt_err_panic: - opts->errors = EXFAT_ERRORS_PANIC; - break; - case Opt_err_ro: - opts->errors = EXFAT_ERRORS_RO; - break; - case Opt_debug: - *debug = 1; - break; -#ifdef CONFIG_STAGING_EXFAT_DISCARD - case Opt_discard: - opts->discard = 1; - break; -#endif /* CONFIG_STAGING_EXFAT_DISCARD */ - case Opt_utf8_hack: - break; - default: - if (!silent) - pr_err("[EXFAT] Unrecognized mount option %s or missing value\n", - p); - return -EINVAL; - } - } - -out: - if (opts->allow_utime == U16_MAX) - opts->allow_utime = ~opts->fs_dmask & 0022; - - return 0; -} - -static void exfat_hash_init(struct super_block *sb) -{ - struct exfat_sb_info *sbi = EXFAT_SB(sb); - int i; - - spin_lock_init(&sbi->inode_hash_lock); - for (i = 0; i < EXFAT_HASH_SIZE; i++) - INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); -} - -static int exfat_read_root(struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct fs_info_t *p_fs = &sbi->fs_info; - struct timespec64 curtime; - struct dir_entry_t info; - - EXFAT_I(inode)->fid.dir.dir = p_fs->root_dir; - EXFAT_I(inode)->fid.dir.flags = 0x01; - EXFAT_I(inode)->fid.entry = -1; - EXFAT_I(inode)->fid.start_clu = p_fs->root_dir; - EXFAT_I(inode)->fid.flags = 0x01; - EXFAT_I(inode)->fid.type = TYPE_DIR; - EXFAT_I(inode)->fid.rwoffset = 0; - EXFAT_I(inode)->fid.hint_last_off = -1; - - EXFAT_I(inode)->target = NULL; - - ffsReadStat(inode, &info); - - inode->i_uid = sbi->options.fs_uid; - inode->i_gid = sbi->options.fs_gid; - INC_IVERSION(inode); - inode->i_generation = 0; - inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, 0777); - inode->i_op = &exfat_dir_inode_operations; - inode->i_fop = &exfat_dir_operations; - - i_size_write(inode, info.Size); - inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) - & ~((loff_t)p_fs->cluster_size - 1)) >> 9; - EXFAT_I(inode)->i_pos = ((loff_t)p_fs->root_dir << 32) | 0xffffffff; - EXFAT_I(inode)->mmu_private = i_size_read(inode); - - exfat_save_attr(inode, ATTR_SUBDIR); - curtime = current_time(inode); - inode->i_mtime = curtime; - inode->i_atime = curtime; - inode->i_ctime = curtime; - set_nlink(inode, info.NumSubdirs + 2); - - return 0; -} - -static void setup_dops(struct super_block *sb) -{ - if (EXFAT_SB(sb)->options.casesensitive == 0) - sb->s_d_op = &exfat_ci_dentry_ops; - else - sb->s_d_op = &exfat_dentry_ops; -} - -static int exfat_fill_super(struct super_block *sb, void *data, int silent) -{ - struct inode *root_inode = NULL; - struct exfat_sb_info *sbi; - int debug, ret; - long error; - - /* - * GFP_KERNEL is ok here, because while we do hold the - * supeblock lock, memory pressure can't call back into - * the filesystem, since we're only just about to mount - * it and have no inodes etc active! - */ - sbi = kvzalloc(sizeof(*sbi), GFP_KERNEL); - if (!sbi) - return -ENOMEM; - mutex_init(&sbi->s_lock); - sb->s_fs_info = sbi; - sb->s_flags |= SB_NODIRATIME; - sb->s_magic = EXFAT_SUPER_MAGIC; - sb->s_op = &exfat_sops; - sb->s_export_op = &exfat_export_ops; - - error = parse_options(data, silent, &debug, &sbi->options); - if (error) - goto out_fail; - - setup_dops(sb); - - error = -EIO; - sb_min_blocksize(sb, 512); - sb->s_maxbytes = 0x7fffffffffffffffLL; /* maximum file size */ - - ret = ffsMountVol(sb); - if (ret) { - if (!silent) - pr_err("[EXFAT] ffsMountVol failed\n"); - - goto out_fail; - } - - /* set up enough so that it can read an inode */ - exfat_hash_init(sb); - - /* - * The low byte of FAT's first entry must have same value with - * media-field. But in real world, too many devices is - * writing wrong value. So, removed that validity check. - * - * if (FAT_FIRST_ENT(sb, media) != first) - */ - - sbi->nls_io = load_nls(sbi->options.iocharset); - - error = -ENOMEM; - root_inode = new_inode(sb); - if (!root_inode) - goto out_fail2; - root_inode->i_ino = EXFAT_ROOT_INO; - SET_IVERSION(root_inode, 1); - - error = exfat_read_root(root_inode); - if (error < 0) - goto out_fail2; - error = -ENOMEM; - exfat_attach(root_inode, EXFAT_I(root_inode)->i_pos); - insert_inode_hash(root_inode); - sb->s_root = d_make_root(root_inode); - if (!sb->s_root) { - pr_err("[EXFAT] Getting the root inode failed\n"); - goto out_fail2; - } - - return 0; - -out_fail2: - ffsUmountVol(sb); -out_fail: - if (root_inode) - iput(root_inode); - sb->s_fs_info = NULL; - exfat_free_super(sbi); - return error; -} - -static struct dentry *exfat_fs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) -{ - return mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super); -} - -static void init_once(void *foo) -{ - struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; - - INIT_HLIST_NODE(&ei->i_hash_fat); - inode_init_once(&ei->vfs_inode); -} - -static int __init exfat_init_inodecache(void) -{ - exfat_inode_cachep = kmem_cache_create("exfat_inode_cache", - sizeof(struct exfat_inode_info), - 0, - (SLAB_RECLAIM_ACCOUNT | - SLAB_MEM_SPREAD), - init_once); - if (!exfat_inode_cachep) - return -ENOMEM; - return 0; -} - -static void __exit exfat_destroy_inodecache(void) -{ - /* - * Make sure all delayed rcu free inodes are flushed before we - * destroy cache. - */ - rcu_barrier(); - kmem_cache_destroy(exfat_inode_cachep); -} - -#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG -static void exfat_debug_kill_sb(struct super_block *sb) -{ - struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct block_device *bdev = sb->s_bdev; - struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - - long flags; - - if (sbi) { - flags = sbi->debug_flags; - - if (flags & EXFAT_DEBUGFLAGS_INVALID_UMOUNT) { - /* - * invalidate_bdev drops all device cache include - * dirty. We use this to simulate device removal. - */ - mutex_lock(&p_fs->v_mutex); - exfat_fat_release_all(sb); - exfat_buf_release_all(sb); - mutex_unlock(&p_fs->v_mutex); - - invalidate_bdev(bdev); - } - } - - kill_block_super(sb); -} -#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ - -static struct file_system_type exfat_fs_type = { - .owner = THIS_MODULE, - .name = "exfat", - .mount = exfat_fs_mount, -#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG - .kill_sb = exfat_debug_kill_sb, -#else - .kill_sb = kill_block_super, -#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */ - .fs_flags = FS_REQUIRES_DEV, -}; - -static int __init init_exfat(void) -{ - int err; - - BUILD_BUG_ON(sizeof(struct dentry_t) != DENTRY_SIZE); - BUILD_BUG_ON(sizeof(struct dos_dentry_t) != DENTRY_SIZE); - BUILD_BUG_ON(sizeof(struct ext_dentry_t) != DENTRY_SIZE); - BUILD_BUG_ON(sizeof(struct file_dentry_t) != DENTRY_SIZE); - BUILD_BUG_ON(sizeof(struct strm_dentry_t) != DENTRY_SIZE); - BUILD_BUG_ON(sizeof(struct name_dentry_t) != DENTRY_SIZE); - BUILD_BUG_ON(sizeof(struct bmap_dentry_t) != DENTRY_SIZE); - BUILD_BUG_ON(sizeof(struct case_dentry_t) != DENTRY_SIZE); - BUILD_BUG_ON(sizeof(struct volm_dentry_t) != DENTRY_SIZE); - - pr_info("exFAT: Version %s\n", EXFAT_VERSION); - - err = exfat_init_inodecache(); - if (err) - return err; - - err = register_filesystem(&exfat_fs_type); - if (err) - return err; - - return 0; -} - -static void __exit exit_exfat(void) -{ - exfat_destroy_inodecache(); - unregister_filesystem(&exfat_fs_type); -} - -module_init(init_exfat); -module_exit(exit_exfat); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("exFAT Filesystem Driver"); -MODULE_ALIAS_FS("exfat"); diff --git a/drivers/staging/exfat/exfat_upcase.c b/drivers/staging/exfat/exfat_upcase.c deleted file mode 100644 index b91a1faa0e50..000000000000 --- a/drivers/staging/exfat/exfat_upcase.c +++ /dev/null @@ -1,740 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. - */ - -#include <linux/types.h> -#include "exfat.h" - -const u8 uni_upcase[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 -}; |