| /* 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_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_EXFAT_KERNEL_DEBUG */ |
| |
| #ifdef CONFIG_EXFAT_DEBUG_MSG |
| #define DEBUG 1 |
| #else |
| #undef DEBUG |
| #endif |
| |
| #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 |
| |
| /* return values */ |
| #define FFS_SUCCESS 0 |
| #define FFS_MEDIAERR 1 |
| #define FFS_FORMATERR 2 |
| #define FFS_MOUNTED 3 |
| #define FFS_NOTMOUNTED 4 |
| #define FFS_ALIGNMENTERR 5 |
| #define FFS_SEMAPHOREERR 6 |
| #define FFS_INVALIDPATH 7 |
| #define FFS_INVALIDFID 8 |
| #define FFS_NOTFOUND 9 |
| #define FFS_FILEEXIST 10 |
| #define FFS_PERMISSIONERR 11 |
| #define FFS_NOTOPENED 12 |
| #define FFS_MAXOPENED 13 |
| #define FFS_FULL 14 |
| #define FFS_EOF 15 |
| #define FFS_DIRBUSY 16 |
| #define FFS_MEMORYERR 17 |
| #define FFS_NAMETOOLONG 18 |
| #define FFS_ERROR 19 |
| |
| #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_func { |
| s32 (*alloc_cluster)(struct super_block *sb, s32 num_alloc, |
| struct chain_t *p_chain); |
| void (*free_cluster)(struct super_block *sb, struct chain_t *p_chain, |
| s32 do_relse); |
| s32 (*count_used_clusters)(struct super_block *sb); |
| |
| s32 (*init_dir_entry)(struct super_block *sb, struct chain_t *p_dir, |
| s32 entry, u32 type, u32 start_clu, u64 size); |
| s32 (*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); |
| s32 (*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 (*delete_dir_entry)(struct super_block *sb, |
| struct chain_t *p_dir, s32 entry, |
| s32 offset, s32 num_entries); |
| void (*get_uni_name_from_ext_entry)(struct super_block *sb, |
| struct chain_t *p_dir, s32 entry, |
| u16 *uniname); |
| s32 (*count_ext_entries)(struct super_block *sb, |
| struct chain_t *p_dir, s32 entry, |
| struct dentry_t *p_entry); |
| s32 (*calc_num_entries)(struct uni_name_t *p_uniname); |
| |
| u32 (*get_entry_type)(struct dentry_t *p_entry); |
| void (*set_entry_type)(struct dentry_t *p_entry, u32 type); |
| u32 (*get_entry_attr)(struct dentry_t *p_entry); |
| void (*set_entry_attr)(struct dentry_t *p_entry, u32 attr); |
| u8 (*get_entry_flag)(struct dentry_t *p_entry); |
| void (*set_entry_flag)(struct dentry_t *p_entry, u8 flag); |
| u32 (*get_entry_clu0)(struct dentry_t *p_entry); |
| void (*set_entry_clu0)(struct dentry_t *p_entry, u32 clu0); |
| u64 (*get_entry_size)(struct dentry_t *p_entry); |
| void (*set_entry_size)(struct dentry_t *p_entry, u64 size); |
| void (*get_entry_time)(struct dentry_t *p_entry, |
| struct timestamp_t *tp, u8 mode); |
| void (*set_entry_time)(struct dentry_t *p_entry, |
| struct timestamp_t *tp, u8 mode); |
| }; |
| |
| 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 fs_func *fs_func; |
| struct semaphore v_sem; |
| |
| /* 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_EXFAT_DISCARD |
| /* flag on if -o dicard specified and device support discard() */ |
| unsigned char discard; |
| #endif /* CONFIG_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_EXFAT_KERNEL_DEBUG |
| long debug_flags; |
| #endif /* CONFIG_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_dosname_cmp(struct super_block *sb, u8 *a, u8 *b); |
| int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b); |
| void nls_uniname_to_dosname(struct super_block *sb, |
| struct dos_name_t *p_dosname, |
| struct uni_name_t *p_uniname, bool *p_lossy); |
| void nls_dosname_to_uniname(struct super_block *sb, |
| struct uni_name_t *p_uniname, |
| struct dos_name_t *p_dosname); |
| 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 buf_init(struct super_block *sb); |
| void buf_shutdown(struct super_block *sb); |
| int FAT_read(struct super_block *sb, u32 loc, u32 *content); |
| s32 FAT_write(struct super_block *sb, u32 loc, u32 content); |
| u8 *FAT_getblk(struct super_block *sb, sector_t sec); |
| void FAT_modify(struct super_block *sb, sector_t sec); |
| void FAT_release_all(struct super_block *sb); |
| void FAT_sync(struct super_block *sb); |
| u8 *buf_getblk(struct super_block *sb, sector_t sec); |
| void buf_modify(struct super_block *sb, sector_t sec); |
| void buf_lock(struct super_block *sb, sector_t sec); |
| void buf_unlock(struct super_block *sb, sector_t sec); |
| void buf_release(struct super_block *sb, sector_t sec); |
| void buf_release_all(struct super_block *sb); |
| void 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 clear_cluster(struct super_block *sb, u32 clu); |
| s32 fat_alloc_cluster(struct super_block *sb, s32 num_alloc, |
| struct chain_t *p_chain); |
| s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, |
| struct chain_t *p_chain); |
| void fat_free_cluster(struct super_block *sb, struct chain_t *p_chain, |
| s32 do_relse); |
| void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain, |
| s32 do_relse); |
| u32 find_last_cluster(struct super_block *sb, struct chain_t *p_chain); |
| s32 count_num_clusters(struct super_block *sb, struct chain_t *dir); |
| s32 fat_count_used_clusters(struct super_block *sb); |
| s32 exfat_count_used_clusters(struct super_block *sb); |
| 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); |
| s32 set_alloc_bitmap(struct super_block *sb, u32 clu); |
| s32 clr_alloc_bitmap(struct super_block *sb, u32 clu); |
| u32 test_alloc_bitmap(struct super_block *sb, u32 clu); |
| 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 */ |
| u32 fat_get_entry_type(struct dentry_t *p_entry); |
| u32 exfat_get_entry_type(struct dentry_t *p_entry); |
| void fat_set_entry_type(struct dentry_t *p_entry, u32 type); |
| void exfat_set_entry_type(struct dentry_t *p_entry, u32 type); |
| u32 fat_get_entry_attr(struct dentry_t *p_entry); |
| u32 exfat_get_entry_attr(struct dentry_t *p_entry); |
| void fat_set_entry_attr(struct dentry_t *p_entry, u32 attr); |
| void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr); |
| u8 fat_get_entry_flag(struct dentry_t *p_entry); |
| u8 exfat_get_entry_flag(struct dentry_t *p_entry); |
| void fat_set_entry_flag(struct dentry_t *p_entry, u8 flag); |
| void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flag); |
| u32 fat_get_entry_clu0(struct dentry_t *p_entry); |
| u32 exfat_get_entry_clu0(struct dentry_t *p_entry); |
| void fat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu); |
| void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu); |
| u64 fat_get_entry_size(struct dentry_t *p_entry); |
| u64 exfat_get_entry_size(struct dentry_t *p_entry); |
| void fat_set_entry_size(struct dentry_t *p_entry, u64 size); |
| void exfat_set_entry_size(struct dentry_t *p_entry, u64 size); |
| struct timestamp_t *tm_current(struct timestamp_t *tm); |
| void fat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, |
| u8 mode); |
| void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp, |
| u8 mode); |
| void fat_set_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); |
| s32 fat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir, s32 entry, |
| u32 type, u32 start_clu, u64 size); |
| s32 exfat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir, |
| s32 entry, u32 type, u32 start_clu, u64 size); |
| s32 fat_init_ext_dir_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); |
| s32 exfat_init_ext_dir_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); |
| void init_dos_entry(struct dos_dentry_t *ep, u32 type, u32 start_clu); |
| void init_ext_entry(struct ext_dentry_t *ep, s32 order, u8 chksum, |
| u16 *uniname); |
| void init_file_entry(struct file_dentry_t *ep, u32 type); |
| void init_strm_entry(struct strm_dentry_t *ep, u8 flags, u32 start_clu, |
| u64 size); |
| void init_name_entry(struct name_dentry_t *ep, u16 *uniname); |
| void fat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, |
| s32 entry, s32 order, s32 num_entries); |
| void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, |
| s32 entry, s32 order, s32 num_entries); |
| |
| s32 find_location(struct super_block *sb, struct chain_t *p_dir, s32 entry, |
| sector_t *sector, s32 *offset); |
| struct dentry_t *get_entry_with_sector(struct super_block *sb, sector_t sector, |
| s32 offset); |
| 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 write_whole_entry_set(struct super_block *sb, struct entry_set_cache_t *es); |
| s32 write_partial_entries_in_entry_set(struct super_block *sb, |
| struct entry_set_cache_t *es, |
| struct dentry_t *ep, u32 count); |
| s32 search_deleted_or_unused_entry(struct super_block *sb, |
| struct chain_t *p_dir, s32 num_entries); |
| s32 find_empty_entry(struct inode *inode, struct chain_t *p_dir, |
| s32 num_entries); |
| s32 fat_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); |
| 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); |
| s32 fat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, |
| s32 entry, struct dentry_t *p_entry); |
| s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir, |
| s32 entry, struct dentry_t *p_entry); |
| 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); |
| void get_uni_name_from_dos_entry(struct super_block *sb, |
| struct dos_dentry_t *ep, |
| struct uni_name_t *p_uniname, u8 mode); |
| void fat_get_uni_name_from_ext_entry(struct super_block *sb, |
| struct chain_t *p_dir, s32 entry, |
| u16 *uniname); |
| void exfat_get_uni_name_from_ext_entry(struct super_block *sb, |
| struct chain_t *p_dir, s32 entry, |
| u16 *uniname); |
| s32 extract_uni_name_from_ext_entry(struct ext_dentry_t *ep, |
| u16 *uniname, s32 order); |
| s32 extract_uni_name_from_name_entry(struct name_dentry_t *ep, |
| u16 *uniname, s32 order); |
| s32 fat_generate_dos_name(struct super_block *sb, struct chain_t *p_dir, |
| struct dos_name_t *p_dosname); |
| void fat_attach_count_to_dos_name(u8 *dosname, s32 count); |
| s32 fat_calc_num_entries(struct uni_name_t *p_uniname); |
| s32 exfat_calc_num_entries(struct uni_name_t *p_uniname); |
| u8 calc_checksum_1byte(void *data, s32 len, u8 chksum); |
| u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type); |
| u32 calc_checksum_4byte(void *data, s32 len, u32 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); |
| s32 resolve_name(u8 *name, u8 **arg); |
| |
| /* file operation functions */ |
| s32 fat16_mount(struct super_block *sb, struct pbr_sector_t *p_pbr); |
| s32 fat32_mount(struct super_block *sb, struct pbr_sector_t *p_pbr); |
| 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 bdev_open(struct super_block *sb); |
| void bdev_close(struct super_block *sb); |
| int bdev_read(struct super_block *sb, sector_t secno, |
| struct buffer_head **bh, u32 num_secs, bool read); |
| int bdev_write(struct super_block *sb, sector_t secno, |
| struct buffer_head *bh, u32 num_secs, bool sync); |
| int bdev_sync(struct super_block *sb); |
| |
| extern const u8 uni_upcase[]; |
| #endif /* _EXFAT_H */ |