1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
*/
#ifndef _LIBEXFAT_H
#include <stdbool.h>
#include <sys/types.h>
#include <wchar.h>
#include <limits.h>
typedef __u32 clus_t;
#define KB (1024)
#define MB (1024*1024)
#define GB (1024UL*1024UL*1024UL)
#define __round_mask(x, y) ((__typeof__(x))((y)-1))
#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
#define round_down(x, y) ((x) & ~__round_mask(x, y))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define DIV_ROUND_UP(__i, __d) (((__i) + (__d) - 1) / (__d))
#define EXFAT_MIN_NUM_SEC_VOL (2048)
#define EXFAT_MAX_NUM_SEC_VOL ((2 << 64) - 1)
#define EXFAT_MAX_NUM_CLUSTER (0xFFFFFFF5)
#define DEFAULT_BOUNDARY_ALIGNMENT (1024*1024)
#define DEFAULT_SECTOR_SIZE (512)
#define VOLUME_LABEL_BUFFER_SIZE (VOLUME_LABEL_MAX_LEN*MB_LEN_MAX+1)
/* Upcase table macro */
#define EXFAT_UPCASE_TABLE_CHARS (0x10000)
#define EXFAT_UPCASE_TABLE_SIZE (5836)
/* Flags for tune.exfat and exfatlabel */
#define EXFAT_GET_VOLUME_LABEL 0x01
#define EXFAT_SET_VOLUME_LABEL 0x02
#define EXFAT_GET_VOLUME_SERIAL 0x03
#define EXFAT_SET_VOLUME_SERIAL 0x04
#define EXFAT_GET_VOLUME_GUID 0x05
#define EXFAT_SET_VOLUME_GUID 0x06
#define EXFAT_MAX_SECTOR_SIZE 4096
#define EXFAT_CLUSTER_SIZE(pbr) (1 << ((pbr)->bsx.sect_size_bits + \
(pbr)->bsx.sect_per_clus_bits))
#define EXFAT_SECTOR_SIZE(pbr) (1 << (pbr)->bsx.sect_size_bits)
#define EXFAT_MAX_HASH_COUNT (UINT16_MAX + 1)
enum {
BOOT_SEC_IDX = 0,
EXBOOT_SEC_IDX,
EXBOOT_SEC_NUM = 8,
OEM_SEC_IDX,
RESERVED_SEC_IDX,
CHECKSUM_SEC_IDX,
BACKUP_BOOT_SEC_IDX,
};
struct exfat_blk_dev {
int dev_fd;
int verify_fd;
unsigned long long offset;
unsigned long long size;
unsigned int sector_size;
unsigned int sector_size_bits;
unsigned long long num_sectors;
unsigned int num_clusters;
unsigned int cluster_size;
bool isblk;
};
struct exfat_user_input {
const char *dev_name;
bool writeable;
unsigned int sector_size;
unsigned int cluster_size;
unsigned int sec_per_clu;
unsigned int boundary_align;
bool pack_bitmap;
bool quick;
bool verify;
bool discard;
__u16 volume_label[VOLUME_LABEL_MAX_LEN];
int volume_label_len;
unsigned int volume_serial;
const char *guid;
unsigned char *fat_table_buff;
};
struct exfat;
struct exfat_inode;
#ifdef WORDS_BIGENDIAN
typedef __u8 bitmap_t;
#else
typedef __u32 bitmap_t;
#endif
#define BITS_PER (sizeof(bitmap_t) * 8)
#define BIT_MASK(__c) (1 << ((__c) % BITS_PER))
#define BIT_ENTRY(__c) ((__c) / BITS_PER)
#define EXFAT_BITMAP_SIZE(__c_count) \
(DIV_ROUND_UP(__c_count, BITS_PER) * sizeof(bitmap_t))
#define BITMAP_GET(bmap, bit) \
(((bitmap_t *)(bmap))[BIT_ENTRY(bit)] & BIT_MASK(bit))
#define BITMAP_SET(bmap, bit) \
(((bitmap_t *)(bmap))[BIT_ENTRY(bit)] |= BIT_MASK(bit))
#define BITMAP_CLEAR(bmap, bit) \
(((bitmap_t *)(bmap))[BIT_ENTRY(bit)] &= ~BIT_MASK(bit))
static inline bool exfat_bitmap_get(char *bmap, clus_t c)
{
clus_t cc = c - EXFAT_FIRST_CLUSTER;
return BITMAP_GET(bmap, cc);
}
static inline void exfat_bitmap_set(char *bmap, clus_t c)
{
clus_t cc = c - EXFAT_FIRST_CLUSTER;
BITMAP_SET(bmap, cc);
}
static inline void exfat_bitmap_clear(char *bmap, clus_t c)
{
clus_t cc = c - EXFAT_FIRST_CLUSTER;
(((bitmap_t *)(bmap))[BIT_ENTRY(cc)] &= ~BIT_MASK(cc));
}
void exfat_bitmap_set_range(struct exfat *exfat, char *bitmap,
clus_t start_clus, clus_t count);
int exfat_bitmap_find_zero(struct exfat *exfat, char *bmap,
clus_t start_clu, clus_t *next);
int exfat_bitmap_find_one(struct exfat *exfat, char *bmap,
clus_t start_clu, clus_t *next);
void show_version(void);
wchar_t exfat_bad_char(wchar_t w);
void boot_calc_checksum(unsigned char *sector, unsigned short size,
bool is_boot_sec, __le32 *checksum);
void init_user_input(struct exfat_user_input *ui);
int exfat_get_blk_dev_info(struct exfat_user_input *ui,
struct exfat_blk_dev *bd);
ssize_t exfat_read(int fd, void *buf, size_t size, off_t offset);
ssize_t exfat_write(int fd, void *buf, size_t size, off_t offset);
ssize_t exfat_write_zero(int fd, size_t size, off_t offset);
int exfat_discard_blocks(int fd, uint64_t start, uint64_t len);
size_t exfat_utf16_len(const __le16 *str, size_t max_size);
ssize_t exfat_utf16_enc(const char *in_str, __u16 *out_str, size_t out_size);
ssize_t exfat_utf16_dec(const __u16 *in_str, size_t in_len,
char *out_str, size_t out_size);
off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd);
int exfat_read_volume_label(struct exfat *exfat);
int exfat_set_volume_label(struct exfat *exfat, char *label_input);
int __exfat_set_volume_guid(struct exfat_dentry *dentry, const char *guid);
int exfat_read_volume_guid(struct exfat *exfat);
int exfat_set_volume_guid(struct exfat *exfat, const char *guid);
int exfat_read_sector(struct exfat_blk_dev *bd, void *buf,
unsigned int sec_off);
int exfat_write_sector(struct exfat_blk_dev *bd, void *buf,
unsigned int sec_off);
int exfat_write_checksum_sector(struct exfat_blk_dev *bd,
struct exfat_user_input *ui, unsigned int checksum,
bool is_backup);
char *exfat_conv_volume_label(struct exfat_dentry *vol_entry);
int exfat_show_volume_serial(int fd);
int exfat_set_volume_serial(struct exfat_blk_dev *bd,
struct exfat_user_input *ui);
unsigned int exfat_clus_to_blk_dev_off(struct exfat_blk_dev *bd,
unsigned int clu_off, unsigned int clu);
int exfat_get_next_clus(struct exfat *exfat, clus_t clus, clus_t *next);
int exfat_get_inode_next_clus(struct exfat *exfat, struct exfat_inode *node,
clus_t clus, clus_t *next);
int exfat_get_clus(struct exfat *exfat, struct exfat_inode *node,
clus_t index, clus_t *ret_clu);
int exfat_set_fat(struct exfat *exfat, clus_t clus, clus_t next_clus);
off_t exfat_s2o(struct exfat *exfat, off_t sect);
off_t exfat_c2o(struct exfat *exfat, unsigned int clus);
int exfat_o2c(struct exfat *exfat, off_t device_offset,
unsigned int *clu, unsigned int *offset);
bool exfat_heap_clus(struct exfat *exfat, clus_t clus);
int exfat_root_clus_count(struct exfat *exfat);
int read_boot_sect(struct exfat_blk_dev *bdev, struct pbr **bs);
int exfat_parse_ulong(const char *s, unsigned long *out);
int exfat_check_name(__le16 *utf16_name, int len);
int exfat_check_written_data(struct exfat_blk_dev *bd, const void *buf,
size_t len, off_t off,
const char *what);
/*
* Exfat Print
*/
extern unsigned int print_level;
#define EXFAT_ERROR (1)
#define EXFAT_INFO (2)
#define EXFAT_DEBUG (3)
#define exfat_msg(level, dir, fmt, ...) \
do { \
if (print_level >= level) { \
fprintf(dir, fmt, ##__VA_ARGS__); \
} \
} while (0) \
#define exfat_err(fmt, ...) exfat_msg(EXFAT_ERROR, stderr, \
fmt, ##__VA_ARGS__)
#define exfat_info(fmt, ...) exfat_msg(EXFAT_INFO, stdout, \
fmt, ##__VA_ARGS__)
#define exfat_debug(fmt, ...) exfat_msg(EXFAT_DEBUG, stdout, \
"[%s:%4d] " fmt, __func__, \
__LINE__, ##__VA_ARGS__)
#endif /* !_LIBEXFAT_H */
|