/* SPDX-License-Identifier: GPL-2.0+ */ /* * R/O exFAT filesystem implementation * */ #ifndef _EXFAT_H_ #define _EXFAT_H_ #include #include /* Maximum Long File Name length supported here is 128 UTF-16 code units */ #define EXFAT_MAXLEN_BYTES 256 /* Maximum LFN buffer in bytes */ #define EXFAT_MAXSEQ 9 /* Up to 9 of 13 2-byte UTF-16 entries */ #define EXFAT_PREFETCH_BLOCKS 2 #ifndef CONFIG_FS_EXFAT_MAX_CLUSTSIZE #define CONFIG_FS_EXFAT_MAX_CLUSTSIZE (256*1024) #endif #define EXFAT_MAX_CLUSTSIZE CONFIG_FS_EXFAT_MAX_CLUSTSIZE #define EXFAT_DIRENTSPERBLOCK (mydata->sect_size / EXFAT_SIZE_PER_ENTRY) #define EXFAT_DIRENTSPERCLUST ((mydata->clust_size * mydata->sect_size) / \ EXFAT_SIZE_PER_ENTRY) #define FATBUFBLOCKS 6 #define FATBUFSIZE (mydata->sect_size * FATBUFBLOCKS) #define EXFATBUFSIZE (FATBUFSIZE/4) /* Maximum number of entry for long file name according to spec */ #define MAX_LFN_SLOT 20 /* Filesystem identifiers */ #define EXFAT_SIGN "EXFAT " #define EXFAT_SIGNLEN 8 /* File attributes */ #define ATTR_RO 1 #define ATTR_HIDDEN 2 #define ATTR_SYS 4 #define ATTR_VOLUME 8 #define ATTR_DIR 16 #define ATTR_ARCH 32 #define ATTR_EXFAT (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME) /* * Indicates that the entry is the last long entry in a set of long * dir entries */ #define LAST_LONG_ENTRY_MASK 0x40 /* Flags telling whether we should read a file or list a directory */ #define LS_NO 0 #define LS_YES 1 #define LS_DIR 1 #define LS_ROOT 2 #define ISDIRDELIM(c) ((c) == '/' || (c) == '\\') //#define FSTYPE_NONE (-1) #if defined(__linux__) && defined(__KERNEL__) #define FAT2CPU16 le16_to_cpu #define FAT2CPU32 le32_to_cpu #else #if __LITTLE_ENDIAN #define FAT2CPU16(x) (x) #define FAT2CPU32(x) (x) #else #define FAT2CPU16(x) ((((x) & 0x00ff) << 8) | (((x) & 0xff00) >> 8)) #define FAT2CPU32(x) ((((x) & 0x000000ff) << 24) | \ (((x) & 0x0000ff00) << 8) | \ (((x) & 0x00ff0000) >> 8) | \ (((x) & 0xff000000) >> 24)) #endif #endif #define EXFAT_START(strmptr) (FAT2CPU32((strmptr)->first_clus)) #define EXFAT_SIZE(strmptr) ((unsigned long long)FAT2CPU32((strmptr)->valid_data_len[0]) \ + FAT2CPU32((unsigned long long)(strmptr)->valid_data_len[1] << 32)) #define EXFAT_IS_CONTIGUOUS(strmptr) ((strmptr)->flags & EXFAT_ENTRY_CONTIGUOUS ? 1 : 0) #define EXFAT_CHECK_CLUST(x, fatsize) ((x) <= 1 || (x) >= (0xffffff0)) #define START(dent) (FAT2CPU16((dent)->start) \ + (mydata->fatsize != 32 ? 0 : \ (FAT2CPU16((dent)->starthi) << 16))) #define IS_LAST_CLUST(x, fatsize) ((x) >= ((fatsize) != 32 ? \ ((fatsize) != 16 ? 0xff8 : 0xfff8) : \ 0xffffff8)) #define CHECK_CLUST(x, fatsize) ((x) <= 1 || \ (x) >= ((fatsize) != 32 ? \ ((fatsize) != 16 ? 0xff0 : 0xfff0) : \ 0xffffff0)) typedef struct exfat_boot_sector { __u8 ignored[3]; /* Bootstrap code */ char file_system_name[8]; /* Name of fs */ __u8 must_be_zero[53]; /* All 00h */ __u32 partition_offset[2]; __u32 volume_length[2]; /* Number of sectors (if sectors == 0) */ __u32 fat_offset; __u32 fat_length; /* Sectors/FAT */ __u32 cluster_heap_offset; __u32 cluster_count; __u32 first_clus_of_root_dir; __u32 volume_serial_number; __u16 file_system_revision; __u16 volume_flags; __u8 byte_per_sector_shift; __u8 sector_per_clus_shift; __u8 number_of_fats; } exfat_boot_sector; typedef struct exfat_volume_info { __u8 drive_number; /* BIOS drive number */ __u8 reserved; /* Unused */ __u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */ __u8 volume_id[4]; /* Volume ID number */ char volume_label[11]; /* Volume label */ char fs_type[8]; /* Typically FAT12, FAT16, FAT32 or EXFAT */ /* Boot code comes next, all but 2 bytes to fill up sector */ /* Boot sign comes last, 2 bytes */ } exfat_volume_info; #define EXFAT_SIZE_PER_ENTRY 32 #define EXFAT_NAME_ENTRY_MAXCHAR 15 //max characters of each name entry (15) #define EXFAT_NAME_ENTRY_MAXNUM 17 //the max number of name entries (17) #define EXFAT_FILENAME_MAXLEN EXFAT_NAME_ENTRY_MAXCHAR*EXFAT_NAME_ENTRY_MAXNUM //255 #define EXFAT_ENTRYTYPE_INUSE 0x80 #define EXFAT_ENTRY_CONTIGUOUS 0x2 #define EXFAT_ENTRY_TYPE_FILE 0x85 #define EXFAT_ENTRY_TYPE_STREAM 0xC0 #define EXFAT_ENTRY_TYPE_NAME 0xC1 #define EXFAT_ENTRY_TYPE_EMPTY 0x00 #define EXFAT_DELETED_FLAG_FILE 0x05 /* Marks deleted files */ #define EXFAT_DELETED_FLAG_STREAM 0x40 /* Marks deleted files */ #define EXFAT_DELETED_FLAG_NAME 0x41 /* Marks deleted files */ /* MS-DOS EXFAT bitmap directory entry (32 bytes) */ typedef struct { __u8 entry_type; __u8 flags; __u16 reserved[9]; __u32 first_clus; __u32 data_len[2]; } exfat_bitmap_dentry; /* MS-DOS EXFAT file directory entry (32 bytes) */ typedef struct { __u8 entry_type; __u8 second_count; __u16 check_sum; __u16 attrib; __u16 reserved1; __u16 create_time; __u16 create_date; __u16 modify_time; __u16 modify_date; __u16 access_time; __u16 access_date; __u8 create_time_10ms; __u8 modify_time_10ms; __u8 create_utc_offset; __u8 modify_utc_offset; __u8 access_utc_offset; __u8 reserved2[7]; } exfat_file_dentry; /* MS-DOS EXFAT stream extension directory entry (32 bytes) */ typedef struct { __u8 entry_type; __u8 flags; __u8 reserved1; __u8 name_len; __u16 name_hash; __u16 reserved2; __u32 valid_data_len[2]; __u32 reserved3; __u32 first_clus; __u32 data_len[2]; } exfat_stream_dentry; /* MS-DOS EXFAT file name directory entry (32 bytes) */ typedef struct { __u8 entry_type; __u8 flags; __u16 name[EXFAT_NAME_ENTRY_MAXCHAR]; } exfat_name_dentry; typedef struct { exfat_file_dentry file_dentry ; exfat_stream_dentry stream_dentry ; exfat_name_dentry name_dentry[EXFAT_NAME_ENTRY_MAXNUM];//although this is an array, but the valid number should be calculate from Stream_Entry } exfat_entry_set; /* * Private filesystem parameters * * Note: FAT buffer has to be 32 bit aligned * (see FAT32 accesses) */ typedef struct { __u8 *fatbuf; /* Current FAT buffer */ int fatsize; /* Size of FAT in bits */ __u32 fatlength; /* Length of FAT in sectors */ __u16 fat_sect; /* Starting sector of the FAT */ __u8 fat_dirty; /* Set if fatbuf has been modified */ __u32 rootdir_sect; /* Start sector of root directory */ __u16 sect_size; /* Size of sectors in bytes */ __u16 clust_size; /* Size of clusters in sectors */ int data_begin; /* The sector of the first cluster, can be negative */ int fatbufnum; /* Used by get_fatent, init to -1 */ int rootdir_size; /* Size of root dir for non-FAT32 */ __u32 root_cluster; /* First cluster of root dir for FAT32 */ u32 total_sect; /* Number of sectors */ int fats; /* Number of FATs */ } exfat_fsdata; static inline u32 exfat_clust_to_sect(exfat_fsdata *fsdata, u32 clust) { return fsdata->data_begin + clust * fsdata->clust_size; } int file_exfat_detectfs(void); int exfat_ls(const char *dir); int exfat_exists(const char *filename); int exfat_size(const char *filename, loff_t *size); int file_exfat_read_at(const char *filename, loff_t pos, void *buffer, loff_t maxsize, loff_t *actread); int file_exfat_read(const char *filename, void *buffer, int maxsize); int exfat_set_blk_dev(struct blk_desc *rbdd, disk_partition_t *info); int exfat_register_device(struct blk_desc *dev_desc, int part_no); int file_exfat_write(const char *filename, void *buf, loff_t offset, loff_t len, loff_t *actwrite); int exfat_read_file(const char *filename, void *buf, loff_t offset, loff_t len, loff_t *actread); int exfat_opendir(const char *filename, struct fs_dir_stream **dirsp); int exfat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp); void exfat_closedir(struct fs_dir_stream *dirs); int exfat_unlink(const char *filename); int exfat_mkdir(const char *dirname); void exfat_close(void); #endif /* _EXFAT_H_ */