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