252 lines
7.7 KiB
C
Executable File
252 lines
7.7 KiB
C
Executable File
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
/*
|
|
* R/O exFAT filesystem implementation
|
|
*
|
|
*/
|
|
|
|
#ifndef _EXFAT_H_
|
|
#define _EXFAT_H_
|
|
|
|
#include <asm/byteorder.h>
|
|
#include <fs.h>
|
|
|
|
/* 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_ */
|