aboutsummaryrefslogtreecommitdiffstats
path: root/libexfat/exfat.h
blob: 122ac5be75c3ba4803a0b0764762ee21a3ccded6 (plain)
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
/*
	exfat.h (29.08.09)
	Definitions of structures and constants used in exFAT file system
	implementation.

	Free exFAT implementation.
	Copyright (C) 2010-2015  Andrew Nayenko

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef EXFAT_H_INCLUDED
#define EXFAT_H_INCLUDED

#include "config.h"
#include "compiler.h"
#include "exfatfs.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <sys/types.h>

#define EXFAT_NAME_MAX 256
#define EXFAT_ATTRIB_CONTIGUOUS 0x10000
#define EXFAT_ATTRIB_CACHED     0x20000
#define EXFAT_ATTRIB_DIRTY      0x40000
#define EXFAT_ATTRIB_UNLINKED   0x80000
#define IS_CONTIGUOUS(node) (((node).flags & EXFAT_ATTRIB_CONTIGUOUS) != 0)
#define SECTOR_SIZE(sb) (1 << (sb).sector_bits)
#define CLUSTER_SIZE(sb) (SECTOR_SIZE(sb) << (sb).spc_bits)
#define CLUSTER_INVALID(c) \
	((c) < EXFAT_FIRST_DATA_CLUSTER || (c) > EXFAT_LAST_DATA_CLUSTER)

#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define DIV_ROUND_UP(x, d) (((x) + (d) - 1) / (d))
#define ROUND_UP(x, d) (DIV_ROUND_UP(x, d) * (d))
#define UTF8_BYTES(c) ((c) * 6) /* UTF-8 character can occupy up to 6 bytes */

#define BMAP_SIZE(count) (ROUND_UP(count, sizeof(bitmap_t) * 8) / 8)
#define BMAP_BLOCK(index) ((index) / sizeof(bitmap_t) / 8)
#define BMAP_MASK(index) ((bitmap_t) 1 << ((index) % (sizeof(bitmap_t) * 8)))
#define BMAP_GET(bitmap, index) \
	((bitmap)[BMAP_BLOCK(index)] & BMAP_MASK(index))
#define BMAP_SET(bitmap, index) \
	((bitmap)[BMAP_BLOCK(index)] |= BMAP_MASK(index))
#define BMAP_CLR(bitmap, index) \
	((bitmap)[BMAP_BLOCK(index)] &= ~BMAP_MASK(index))

/* The size of off_t type must be 64 bits. File systems larger than 2 GB will
   be corrupted with 32-bit off_t. */
STATIC_ASSERT(sizeof(off_t) == 8);

struct exfat_node
{
	struct exfat_node* parent;
	struct exfat_node* child;
	struct exfat_node* next;
	struct exfat_node* prev;

	int references;
	uint32_t fptr_index;
	cluster_t fptr_cluster;
	cluster_t entry_cluster;
	off_t entry_offset;
	cluster_t start_cluster;
	int flags;
	uint64_t size;
	time_t mtime, atime;
	le16_t name[EXFAT_NAME_MAX + 1];
};

enum exfat_mode
{
	EXFAT_MODE_RO,
	EXFAT_MODE_RW,
	EXFAT_MODE_ANY,
};

struct exfat_dev;

struct exfat
{
	struct exfat_dev* dev;
	struct exfat_super_block* sb;
	le16_t* upcase;
	size_t upcase_chars;
	struct exfat_node* root;
	struct
	{
		cluster_t start_cluster;
		uint32_t size;				/* in bits */
		bitmap_t* chunk;
		uint32_t chunk_size;		/* in bits */
		bool dirty;
	}
	cmap;
	char label[UTF8_BYTES(EXFAT_ENAME_MAX) + 1];
	void* zero_cluster;
	int dmask, fmask;
	uid_t uid;
	gid_t gid;
	int ro;
	bool noatime;
};

/* in-core nodes iterator */
struct exfat_iterator
{
	struct exfat_node* parent;
	struct exfat_node* current;
};

struct exfat_human_bytes
{
	uint64_t value;
	const char* unit;
};

extern int exfat_errors;

void exfat_bug(const char* format, ...) PRINTF NORETURN;
void exfat_error(const char* format, ...) PRINTF;
void exfat_warn(const char* format, ...) PRINTF;
void exfat_debug(const char* format, ...) PRINTF;

struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode);
int exfat_close(struct exfat_dev* dev);
int exfat_fsync(struct exfat_dev* dev);
enum exfat_mode exfat_get_mode(const struct exfat_dev* dev);
off_t exfat_get_size(const struct exfat_dev* dev);
off_t exfat_seek(struct exfat_dev* dev, off_t offset, int whence);
ssize_t exfat_read(struct exfat_dev* dev, void* buffer, size_t size);
ssize_t exfat_write(struct exfat_dev* dev, const void* buffer, size_t size);
ssize_t exfat_pread(struct exfat_dev* dev, void* buffer, size_t size,
		off_t offset);
ssize_t exfat_pwrite(struct exfat_dev* dev, const void* buffer, size_t size,
		off_t offset);
ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node,
		void* buffer, size_t size, off_t offset);
ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node,
		const void* buffer, size_t size, off_t offset);

int exfat_opendir(struct exfat* ef, struct exfat_node* dir,
		struct exfat_iterator* it);
void exfat_closedir(struct exfat* ef, struct exfat_iterator* it);
struct exfat_node* exfat_readdir(struct exfat* ef, struct exfat_iterator* it);
int exfat_lookup(struct exfat* ef, struct exfat_node** node,
		const char* path);
int exfat_split(struct exfat* ef, struct exfat_node** parent,
		struct exfat_node** node, le16_t* name, const char* path);

off_t exfat_c2o(const struct exfat* ef, cluster_t cluster);
cluster_t exfat_next_cluster(const struct exfat* ef,
		const struct exfat_node* node, cluster_t cluster);
cluster_t exfat_advance_cluster(const struct exfat* ef,
		struct exfat_node* node, uint32_t count);
int exfat_flush(struct exfat* ef);
int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size,
		bool erase);
uint32_t exfat_count_free_clusters(const struct exfat* ef);
int exfat_find_used_sectors(const struct exfat* ef, off_t* a, off_t* b);

void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
		struct stat* stbuf);
void exfat_get_name(const struct exfat_node* node, char* buffer, size_t n);
uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry);
uint16_t exfat_add_checksum(const void* entry, uint16_t sum);
le16_t exfat_calc_checksum(const struct exfat_entry_meta1* meta1,
		const struct exfat_entry_meta2* meta2, const le16_t* name);
uint32_t exfat_vbr_start_checksum(const void* sector, size_t size);
uint32_t exfat_vbr_add_checksum(const void* sector, size_t size, uint32_t sum);
le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name);
void exfat_humanize_bytes(uint64_t value, struct exfat_human_bytes* hb);
void exfat_print_info(const struct exfat_super_block* sb,
		uint32_t free_clusters);

int utf16_to_utf8(char* output, const le16_t* input, size_t outsize,
		size_t insize);
int utf8_to_utf16(le16_t* output, const char* input, size_t outsize,
		size_t insize);
size_t utf16_length(const le16_t* str);

struct exfat_node* exfat_get_node(struct exfat_node* node);
void exfat_put_node(struct exfat* ef, struct exfat_node* node);
int exfat_cleanup_node(struct exfat* ef, struct exfat_node* node);
int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir);
void exfat_reset_cache(struct exfat* ef);
int exfat_flush_node(struct exfat* ef, struct exfat_node* node);
int exfat_unlink(struct exfat* ef, struct exfat_node* node);
int exfat_rmdir(struct exfat* ef, struct exfat_node* node);
int exfat_mknod(struct exfat* ef, const char* path);
int exfat_mkdir(struct exfat* ef, const char* path);
int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path);
void exfat_utimes(struct exfat_node* node, const struct timespec tv[2]);
void exfat_update_atime(struct exfat_node* node);
void exfat_update_mtime(struct exfat_node* node);
const char* exfat_get_label(struct exfat* ef);
int exfat_set_label(struct exfat* ef, const char* label);

int exfat_mount(struct exfat* ef, const char* spec, const char* options);
void exfat_unmount(struct exfat* ef);

time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec);
void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
		uint8_t* centisec);
void exfat_tzset(void);

#endif /* ifndef EXFAT_H_INCLUDED */