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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
|
/* fat.h - Support for FAT filesystems interfaces.
Copyright (C) 2002 Free Software Foundation, Inc.
Written by Marcus Brinkmann.
This file is part of the GNU Hurd.
The GNU Hurd 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, or (at your option)
any later version.
The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#ifndef FAT_H
#define FAT_H
/* Specification of the FAT12/16/32 filesystem format. */
/* Overview
--------
Any FAT fs consists of several regions, which follow immediately
after each other.
Reserved
The reserved region consists of the boot sector, and with it the
BIOS Paramter Block, which contains all necessary data about the
filesystem like sector size, number of clusters etc. It also
holds the filesystem info block.
The reserved region of FAT32 filesystems also hold a backup copy
of the root sector at sector 6 (usually), followed by a backup
copy of the filesystem info sector.
The number of sectors occupied by the reserved region is stored
in the reserved region as well, in the word at offset 14
(reserved_sectors).
FAT
The FAT region contains the File Allocation Table, which is a
linked list of clusters occupied by each file or directory.
There might be multiple FAT tables in the FAT region, for
redundancy.
The number of FATs is stored in the reserved region, in the byte
at offset 16 (nr_of_fat_tables). The number of sectors per FAT is
stored in the word at offset 22 (sectors_per_fat_16) or, if this
is zero (as it is for FAT32), in the doubleword at offset 36
(sectors_per_fat_32).
Root Directory
In FAT12/16, the root directory entries allocate their own region
and are not accessed through the FAT.
The size of this region is determined by the word at offset 17
(nr_of_root_dirents). You have to multiply this with the nr of
bytes per entry, and divide through the number of bytes per
sector, rounding up. On FAT32 filesystems, this region does not
exist, and nr_of_root_dirents is zero. The FAT32 root directory
is accessed through the FAT as any other directory is.
Data
The data region occupies the rest of the filesystem and stores
the actual file and directory data. It is seperated in clusters,
which are indexed in the FAT.
The size of the data region is stored in the word at offset 19
(total_sectors_16) or, if this is zero, in the doubleword at
offset 32 (total_sectors_32).
NOTE that all meta data in a FAT filesystem is stored in little endian
format.
*/
/* The supported FAT types. */
enum fat { FAT12, FAT16, FAT32 };
typedef enum fat fat_t;
/* The FAT type is determined by the number of clusters in the data
region, and nothing else. The maximal number of clusters for a
FAT12 and FAT16 respectively is defined here.
*/
#define FAT12_MAX_NR_OF_CLUSTERS 4084
#define FAT16_MAX_NR_OF_CLUSTERS 65524
#define FAT32_MAX_NR_OF_CLUSTERS (FAT32_BAD_CLUSTER - 1)
struct boot_sector
{
/* Unused. */
unsigned char jump_to_boot_code[3]; /* 0, typ. 0xeb 0x?? 0x90 */
unsigned char oem_name[8]; /* 3, typ. "MSWIN4.1" */
/* Sector and Cluster size.
bytes_per_sector is usually 512, but 1024, 2048, 4096 are also allowed.
sectors_per_cluster is one of 1, 2, 4, 8, 16, 32, 64, 128.
Note that bytes per cluster (product of the two) must be <= 32768. */
unsigned char bytes_per_sector[2]; /* 11 */
unsigned char sectors_per_cluster; /* 13 */
/* Size of the various regions.
reserved_sectors must not be zero and is typically 1 on FAT12/16
filesystems and 32 on FAT32 filesystems.
nr_of_fat_tables must not be zero and is typically 2.
nr_of_root_dirents must be zero on FAT32 filesystems.
For FAT12/16, the value multiplied with DIR_ENTRY_SIZE (32)
should always be a multiple of bytes_per_sector to retain
compatibility. For FAT16, 512 should be used.
total_sectors_16 contains the complete number of sectors if not zero.
If zero, the number of sectors is stored in total_sectors_32. */
unsigned char reserved_sectors[2]; /* 14 */
unsigned char nr_of_fat_tables; /* 16 */
unsigned char nr_of_root_dirents[2]; /* 17 */
unsigned char total_sectors_16[2]; /* 19 */
/* Media descriptor.
Allowed are values between 0xf0 and 0xff.
0xf8 is a fixed hardware (disk), 0xf0 denotes a removable media.
Must be the same as the first byte in the FAT (compatibility
with DOS 1.x). */
unsigned char media_descriptor; /* 21 */
/* Size of one FAT.
On FAT32 systems, this value must be zero and sectors_per_fat_32
used instead. */
unsigned char sectors_per_fat_16[2]; /* 22 */
/* Disk geometry. Unused. */
unsigned char sectors_per_track[2]; /* 24 */
unsigned char nr_of_heads[2]; /* 26 */
unsigned char nr_of_hidden_sectors[4]; /* 28 */
/* See total_sectors_16. */
unsigned char total_sectors_32[4]; /* 32 */
/* FAT specific information.
Starting with offset 36, FAT12/16 filesystems differ from FAT32
filesystems. */
union
{
struct
{
unsigned char drive; /* 36 */
unsigned char reserved; /* 37 */
/* Boot signature.
Value is 0x29.
Indicates that the following three fields
are present. */
unsigned char boot_signature; /* 38 */
/* Identifier.
serial is an unique identifier for removable media.
label is the filesystem label, which must match the label
stored in the root directory entry which has DIR_ATTR_LABEL
set. If no name is specified, the content is "NO NAME ".
fs_type: One of "FAT12 ", "FAT16 ", "FAT ".
Don't use. */
unsigned char serial[4]; /* 39 */
unsigned char label[11]; /* 43 */
unsigned char fs_type[8]; /* 54 */
} fat;
struct
{
/* See sectors_per_fat_16. */
unsigned char sectors_per_fat_32[4]; /* 36 */
/* Extension flags.
Bits 0-3: Zero based nr of active FAT.
Bit 7: If 0, all FATs are active and should be kept up to date.
If 1, only the active FAT (see bits 0-3) should be used.
The rest of the bits are reserved. */
unsigned char extension_flags[2]; /* 40 */
/* Filesystem version.
The high byte is the major number, the low byte the minor version.
Don't mount if either version number is higher than known versions. */
unsigned char fs_version[2]; /* 42 */
/* Root cluster.
The cluster where the root directory starts. */
unsigned char root_cluster[4]; /* 44 */
/* Filesystem Info sector.
The setor number of the filesystem info block in the
reserved area. */
unsigned char fs_info_sector[2]; /* 48 */
/* Backup boot sector.
The sector of the backup copy of the boot sector.
Should be 6, so it can be used even if this field is
corrupted. */
unsigned char backup_boot_sector[2]; /* 50 */
unsigned char reserved1[12]; /* 52 */
/* See fat structure above, with the following exception:
fs_type is "FAT32 ". */
unsigned char drive_number; /* 64 */
unsigned char reserved2; /* 65 */
unsigned char boot_signature; /* 66 */
unsigned char serial[4]; /* 67 */
unsigned char label[11]; /* 71 */
unsigned char fs_type[8]; /* 82 */
} fat32;
} compat;
unsigned char unused[420]; /* 90 */
/* Expected ID at offset 510.
*/
#define BOOT_SECTOR_ID 0xaa55
unsigned char id[2]; /* 510 */
};
/* File System Info Block. */
#define FAT_FS_INFO_LEAD_SIGNATURE 0x41615252L
#define FAT_FS_INFO_STRUCT_SIGNATURE 0x61417272L
#define FAT_FS_INFO_TRAIL_SIGNAURE 0xaa550000L
#define FAT_FS_NR_OF_FREE_CLUSTERS_UNKNOWN 0xffffffffL
#define FAT_FS_NEXT_FREE_CLUSTER_UNKNOWN 0xffffffffL
struct fat_fs_info
{
unsigned char lead_signature[4];
unsigned char reserved1[480];
unsigned char struct_signature[4];
unsigned char nr_of_free_clusters[4];
unsigned char next_free_cluster[4];
unsigned char reserved2[12];
unsigned char trail_signature[4];
};
/* File Allocation Table, special entries. */
#define FAT_FREE_CLUSTER 0
#define FAT12_BAD_CLUSTER 0x0ff7
#define FAT16_BAD_CLUSTER 0xfff7
#define FAT32_BAD_CLUSTER 0x0ffffff7L
#define FAT_BAD_CLUSTER FAT32_BAD_CLUSTER
#define FAT12_EOC 0x0ff8
#define FAT16_EOC 0xfff8
#define FAT32_EOC 0x0ffffff8
#define FAT_EOC FAT32_EOC
/* Directories. */
#define FAT_DIR_REC_LEN 32
#define FAT_DIR_RECORDS(x) FAT_DIR_REC_LEN /* Something else for vfat. */
#define FAT_DIR_ATTR_RDONLY 0x01
#define FAT_DIR_ATTR_HIDDEN 0x02
#define FAT_DIR_ATTR_SYSTEM 0x04
#define FAT_DIR_ATTR_LABEL 0x08
#define FAT_DIR_ATTR_DIR 0x10
#define FAT_DIR_ATTR_ARCHIVE 0x20
#define FAT_DIR_ATTR_LONGNAME (DIR_ATTR_RDONLY | DIR_ATTR_HIDDEN \
| DIR_ATTR_SYSTEM | DIR_ATTR_LABEL)
#define FAT_DIR_NAME_LAST '\x00'
#define FAT_DIR_NAME_DELETED '\xe5'
/* If the first character is this, replace it with FAT_DIR_NAME_DELETED
after checking for it. */
#define FAT_DIR_NAME_REPLACE_DELETED '\x05'
#define FAT_DIR_NAME_DOT ". "
#define FAT_DIR_NAME_DOTDOT ".. "
struct dirrect
{
unsigned char name[11];
unsigned char attribute;
unsigned char reserved;
unsigned char creation_time_centiseconds;
unsigned char creation_time[2];
unsigned char creation_date[2];
unsigned char last_access_date[2];
unsigned char first_cluster_high[2];
unsigned char write_time[2];
unsigned char write_date[2];
unsigned char first_cluster_low[2];
unsigned char file_size[4];
};
#define FAT_NAME_MAX 12 /* VFAT: 255 */
extern vm_offset_t first_data_byte;
extern size_t bytes_per_cluster;
/* A cluster number. */
typedef unsigned long cluster_t;
#define LOG2_CLUSTERS_PER_TABLE 10
#define CLUSTERS_PER_TABLE (1 << LOG2_CLUSTERS_PER_TABLE)
struct cluster_chain
{
struct cluster_chain *next;
cluster_t cluster[CLUSTERS_PER_TABLE];
};
/* Prototyping. */
void fat_read_sblock (void);
void fat_to_epoch (char *, char *, struct timespec *);
void fat_from_epoch (char *, char *, time_t *);
error_t fat_getcluster (struct node *, cluster_t, int, cluster_t *);
void fat_truncate_node (struct node *, cluster_t);
error_t fat_extend_chain (struct node *, cluster_t, int);
int fat_get_freespace (void);
/* Unprocessed superblock. */
extern struct boot_sector *sblock;
/* Processed sblock info. */
extern fat_t fat_type;
extern size_t bytes_per_sector;
extern size_t log2_bytes_per_sector;
extern size_t sectors_per_cluster;
extern size_t bytes_per_cluster;
extern unsigned int log2_bytes_per_cluster;
extern size_t sectors_per_fat;
extern size_t total_sectors;
extern size_t nr_of_root_dir_sectors;
extern size_t first_root_dir_byte;
extern size_t first_data_sector;
extern vm_offset_t first_data_byte;
extern size_t first_fat_sector;
extern cluster_t nr_of_clusters;
/* Numeric conversions for these fields. */
#include <endian.h>
static inline unsigned int
read_dword (unsigned char *addr)
{
#if BYTE_ORDER == LITTLE_ENDIAN
return *(unsigned int *)addr;
#elif BYTE_ORDER == BIG_ENDIAN
return *(unsigned int *)(addr + 4);
#else
return
addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
#endif
}
static inline unsigned int
read_word (unsigned char *addr)
{
#if BYTE_ORDER == LITTLE_ENDIAN
return *(unsigned short *)addr;
#elif BYTE_ORDER == BIG_ENDIAN
return *(unsigned short *)addr + 2;
#else
return addr[0] | (addr[1] << 8);
#endif
}
static inline void
write_dword (unsigned char *addr, unsigned int value)
{
#if BYTE_ORDER == LITTLE_ENDIAN
*(unsigned int *)addr = value;
#elif BYTE_ORDER == BIG_ENDIAN
#error unknown byte order
#else
addr[0] = value & 0xff;
addr[1] = (value >> 8) & 0xff;
addr[2] = (value >> 16) & 0xff;
addr[3] = (value >> 24) & 0xff;
#endif
}
static inline void
write_word (unsigned char *addr, unsigned int value)
{
#if BYTE_ORDER == LITTLE_ENDIAN
*(unsigned short *)addr = value;
#elif BYTE_ORDER == BIG_ENDIAN
#error unknown byte order
#else
addr[0] = value & 0xff;
addr[1] = (value >> 8) & 0xff;
#endif
}
#endif /* FAT_H */
|