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
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_FS_PC_FS_H
#define _SYS_FS_PC_FS_H
#include <sys/thread.h>
#include <sys/ksynch.h>
#include <sys/sysmacros.h>
#include <sys/byteorder.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint16_t pc_cluster16_t;
typedef uint32_t pc_cluster32_t;
/*
* PC (MSDOS) compatible virtual file system.
*
* A main goal of the implementation was to maintain statelessness
* except while files are open. Thus mounting and unmounting merely
* declared the file system name. The user may change disks at almost
* any time without concern (just like the PC). It is assumed that when
* files are open for writing the disk access light will be on, as a
* warning not to change disks. The implementation must, however, detect
* disk change and recover gracefully. It does this by comparing the
* in core entry for a directory to the on disk entry whenever a directory
* is searched. If a discrepancy is found active directories become root and
* active files are marked invalid.
*
* There are only two type of nodes on the PC file system; files and
* directories. These are represented by two separate vnode op vectors,
* and they are kept in two separate tables. Files are known by the
* disk block number and block (cluster) offset of the files directory
* entry. Directories are known by the starting cluster number.
*
* The file system is locked for during each user operation. This is
* done to simplify disk verification error conditions.
*
* Notes on FAT32 support
* ----------------------
* The basic difference between FAT32 and FAT16 is that cluster numbers are now
* 32-bit instead of 16-bit. The FAT is thus an array of 32-bit cluster numbers,
* and because of this the cluster size can be much smaller on a large disk
* (4k, say, on a 1 Gig drive instead of 16k). Unfortunately, the FAT is not
* the only place cluster numbers are stored - the starting cluster is stored
* in the directory entry for a file, and of course it's only 16-bit. Luckily,
* there's a 16-bit OS/2 Extended Attribute field that is now used to store the
* upper 16-bits of the starting cluster number.
*
* Most of the FAT32 changes to pcfs are under 'if it's FAT32' to minimize the
* effect on non-FAT32 filesystems (and still share the code), except for the
* starting cluster changes. It seemed easier to make common functions to
* handle that.
*
* Other changes:
*
* 1. FAT32 partitions are indicated by partition types 0xB and 0xC.
* 2. The boot sector is now 2 sectors, to make room for FAT32 extensions.
* 3. The root directory is no longer stored in a fixed location. Its'
* starting cluster is stored in the extended boot sector.
* 4. "Summary information" is now stored and we need to (at least) maintain
* the number of free clusters or scandisk will be upset. Though the
* sector this info is in is pointed to by the extensions in the boot
* sector, the magic offset of this information is just that so
* far - magic. 0x1e0.
* 5. FAT32 can use the alternate FAT. But we don't.
*
* FAT32 also exposed a latent bug: we bread() each copy of the FAT in one
* big chunk. This is not good on a large FAT32 drive, such as a 1 Gig
* Jaz drive that has 4k clusters, since the FAT becomes 1 Meg in size and
* bread blocks forever. So now we read the FAT in chunks.
*/
/*
* The FAT bootsector uses little-endian multibyte values not aligned at
* a 'native' wordsize. Instead of defining a strange data structure and
* odd accessor methods for some members while using standard C accesses
* for others, we don't bother and just define the structure offsets, and
* a common set of misaligned-littleendian accessor macros.
*
* The "bootsec" and "fat32_bootsec" structures are only provided for
* compatibility with old code including <sys/fs/pc_fs.h> but not used
* by the PCFS kernel driver anymore.
*/
struct bootsec {
uchar_t instr[3];
uchar_t version[8];
uchar_t bps[2]; /* bytes per sector */
uchar_t spcl; /* sectors per allocation unit */
uchar_t res_sec[2]; /* reserved sectors, starting at 0 */
uchar_t nfat; /* number of FATs */
uchar_t rdirents[2]; /* number of root directory entries */
uchar_t numsect[2]; /* old total sectors in logical image */
uchar_t mediadesriptor; /* media descriptor byte */
ushort_t fatsec; /* number of sectors per FAT */
ushort_t spt; /* sectors per track */
ushort_t nhead; /* number of heads */
uint_t hiddensec; /* number of hidden sectors */
uint_t totalsec; /* total sectors in logical image */
};
/*
* FAT32 volumes have a bigger boot sector. They include the normal
* boot sector.
*/
struct fat32_bootsec {
struct bootsec f_bs;
uint32_t f_fatlength; /* size of FAT */
uint16_t f_flags;
uint8_t f_major; /* major filesystem version #? */
uint8_t f_minor; /* minor filesystem version #? */
uint32_t f_rootcluster; /* first cluster in root directory */
uint16_t f_infosector; /* where summary info is */
uint16_t f_backupboot; /* backup boot sector */
uint16_t f_reserved2[6];
};
#define OFF_JMPBOOT 0
#define OFF_OEMNAME 3
#define OFF_BYTESPERSEC 11
#define OFF_SECPERCLUS 13
#define OFF_RSVDSECCNT 14
#define OFF_NUMFATS 16
#define OFF_ROOTENTCNT 17
#define OFF_TOTSEC16 19
#define OFF_MEDIA 21
#define OFF_FATSZ16 22
#define OFF_SECPERTRK 24
#define OFF_NUMHEADS 26
#define OFF_HIDDSEC 28
#define OFF_TOTSEC32 32
#define OFF_BPBSIG 510
#define OFF_DRVNUM16 36
#define OFF_BOOTSIG16 38
#define OFF_VOLID16 39
#define OFF_VOLLAB16 43
#define OFF_FILSYSTYP16 54
#define OFF_FATSZ32 36
#define OFF_EXTFLAGS32 40
#define OFF_FSVER32 42
#define OFF_ROOTCLUS32 44
#define OFF_FSINFO32 48
#define OFF_BKBOOTSEC32 50
#define OFF_DRVNUM32 64
#define OFF_BOOTSIG32 66
#define OFF_VOLID32 67
#define OFF_VOLLAB32 71
#define OFF_FILSYSTYP32 82
#define LE_16_NA(addr) \
(((uint16_t)*((uint8_t *)(addr))) + \
((uint16_t)*((uint8_t *)(addr) + 1) << 8))
#define LE_32_NA(addr) \
(((uint32_t)*((uint8_t *)(addr))) + \
((uint32_t)*((uint8_t *)(addr) + 1) << 8) + \
((uint32_t)*((uint8_t *)(addr) + 2) << 16) + \
((uint32_t)*((uint8_t *)(addr) + 3) << 24))
/*
* Generic FAT BPB fields
*/
#define bpb_jmpBoot(bpb) ((unsigned char *)(bpb))
#define bpb_OEMName(bpb) ((char *)(bpb) + OFF_OEMNAME)
#define bpb_get_BytesPerSec(bpb) LE_16_NA((bpb) + OFF_BYTESPERSEC)
#define bpb_get_SecPerClus(bpb) (((uint8_t *)(bpb))[OFF_SECPERCLUS])
#define bpb_get_RsvdSecCnt(bpb) LE_16_NA((bpb) + OFF_RSVDSECCNT)
#define bpb_get_NumFATs(bpb) (((uint8_t *)(bpb))[OFF_NUMFATS])
#define bpb_get_RootEntCnt(bpb) LE_16_NA((bpb) + OFF_ROOTENTCNT)
#define bpb_get_TotSec16(bpb) LE_16_NA((bpb) + OFF_TOTSEC16)
#define bpb_get_Media(bpb) (((uint8_t *)(bpb))[OFF_MEDIA])
#define bpb_get_FatSz16(bpb) LE_16_NA((bpb) + OFF_FATSZ16)
#define bpb_get_SecPerTrk(bpb) LE_16_NA((bpb) + OFF_SECPERTRK)
#define bpb_get_NumHeads(bpb) LE_16_NA((bpb) + OFF_NUMHEADS)
#define bpb_get_HiddSec(bpb) LE_32_NA((bpb) + OFF_HIDDSEC)
#define bpb_get_TotSec32(bpb) LE_32_NA((bpb) + OFF_TOTSEC32)
#define bpb_get_BPBSig(bpb) LE_16_NA((bpb) + OFF_BPBSIG)
/*
* FAT12/16 extended BPB fields
*/
#define bpb_get_DrvNum16(bpb) (((uint8_t *)(bpb))[OFF_DRVNUM16])
#define bpb_get_BootSig16(bpb) (((uint8_t *)(bpb))[OFF_BOOTSIG16])
#define bpb_VolLab16(bpb) ((char *)(bpb) + OFF_VOLLAB16)
#define bpb_FilSysType16(bpb) ((char *)(bpb) + OFF_FILSYSTYP16)
#define bpb_get_VolID16(bpb) LE_32_NA((bpb) + OFF_VOLID16)
/*
* FAT32 extended BPB fields
*/
#define bpb_get_FatSz32(bpb) LE_32_NA((bpb) + OFF_FATSZ32)
#define bpb_get_ExtFlags32(bpb) LE_16_NA((bpb) + OFF_EXTFLAGS32)
#define bpb_get_FSVer32(bpb) LE_16_NA((bpb) + OFF_FSVER32)
#define bpb_get_RootClus32(bpb) LE_32_NA((bpb) + OFF_ROOTCLUS32)
#define bpb_get_FSInfo32(bpb) LE_16_NA((bpb) + OFF_FSINFO32)
#define bpb_get_BkBootSec32(bpb) LE_16_NA((bpb) + OFF_BKBOOTSEC32)
#define bpb_get_DrvNum32(bpb) (((uint8_t *)(bpb))[OFF_DRVNUM32])
#define bpb_get_BootSig32(bpb) (((uint8_t *)(bpb))[OFF_BOOTSIG32])
#define bpb_get_VolID32(bpb) LE_32_NA((bpb) + OFF_VOLID32)
#define bpb_VolLab32(bpb) ((char *)(bpb) + OFF_VOLLAB32)
#define bpb_FilSysType32(bpb) ((char *)(bpb) + OFF_FILSYSTYP32)
/*
* Validators
*/
#define VALID_SECSIZE(s) \
(s == 512 || s == 1024 || s == 2048 || s == 4096)
#define VALID_SPCL(s) (ISP2((s)) && (unsigned int)(s) <= 128)
#define VALID_CLSIZE(s) (ISP2((s)) && (unsigned int)(s) <= (64 * 1024))
#define VALID_NUMFATS(n) ((n) > 0 && (n) < 8)
#define VALID_RSVDSEC(s) ((s) > 0)
#define VALID_BPBSIG(sig) ((sig) == MBB_MAGIC)
#define VALID_BOOTSIG(sig) ((sig) == 0x29)
#define VALID_MEDIA(m) ((m) == 0xF0 || ((m) >= 0xF8 && (m) <= 0xFF))
/*
* this might require a change for codepage support. In particular,
* pc_validchar() cannot be a macro anymore if codepages get involved.
*/
#define VALID_VOLLAB(l) ( \
pc_validchar((l)[0]) && pc_validchar((l)[1]) && \
pc_validchar((l)[2]) && pc_validchar((l)[3]) && \
pc_validchar((l)[4]) && pc_validchar((l)[5]) && \
pc_validchar((l)[6]) && pc_validchar((l)[7]) && \
pc_validchar((l)[8]) && pc_validchar((l)[9]) && \
pc_validchar((l)[10]))
/*
* We might actually use the 'validchar' checks as well; it only needs
* to be printable. Should this ever caused failed media recognition,
* we can change it. Many ISVs put different strings into the "oemname"
* field.
*/
#define VALID_OEMNAME(nm) ( \
bcmp((nm), "MSDOS", 5) == 0 || bcmp((nm), "MSWIN", 5) == 0)
#define VALID_FSTYPSTR16(typ) (bcmp((typ), "FAT", 3) == 0)
#define VALID_FSTYPSTR32(typ) (bcmp((typ), "FAT32", 5) == 0)
#define VALID_JMPBOOT(b) ( \
((b)[0] == 0xeb && (b)[2] == 0x90) || (b)[0] == 0xe9)
#define VALID_FSVER32(v) ((v) == PCFS_SUPPORTED_FSVER)
/*
* Can we check this properly somehow ? There should be a better way.
* The FAT spec doesn't mention reserved bits need to be zero ...
*/
#define VALID_EXTFLAGS(flags) (((flags) & 0x8f) == (flags))
/*
* Validation results
*/
#define BPB_SECSIZE_OK (1 << 0) /* ok: 512/1024/2048/4096 */
#define BPB_OEMNAME_OK (1 << 1) /* "MSDOS" or "MSWIN" */
#define BPB_JMPBOOT_OK (1 << 2) /* 16bit "jmp" / "call" */
#define BPB_SECPERCLUS_OK (1 << 3) /* power of 2, [1 .. 128] */
#define BPB_RSVDSECCNT_OK (1 << 4) /* cannot be zero */
#define BPB_NUMFAT_OK (1 << 5) /* >= 1, <= 8 */
#define BPB_ROOTENTCNT_OK (1 << 6) /* 0 on FAT32, != 0 else */
#define BPB_TOTSEC_OK (1 << 7) /* smaller than volume */
#define BPB_TOTSEC16_OK (1 << 8) /* 0 on FAT32, != 0 on FAT12 */
#define BPB_TOTSEC32_OK (1 << 9) /* 0 on FAT12, != 0 on FAT32 */
#define BPB_MEDIADESC_OK (1 << 10) /* 0xf0 or 0xf8..0xff */
#define BPB_FATSZ_OK (1 << 11) /* [nclusters], no smaller */
#define BPB_FATSZ16_OK (1 << 12) /* 0 on FAT32, != 0 else */
#define BPB_FATSZ32_OK (1 << 13) /* non-zero on FAT32 */
#define BPB_BPBSIG_OK (1 << 14) /* 0x55, 0xAA */
#define BPB_BOOTSIG16_OK (1 << 15) /* 0x29 - if present */
#define BPB_BOOTSIG32_OK (1 << 16) /* 0x29 - unless SYSLINUX2.x */
#define BPB_FSTYPSTR16_OK (1 << 17) /* At least "FAT" */
#define BPB_FSTYPSTR32_OK (1 << 18) /* "FAT32" */
#define BPB_EXTFLAGS_OK (1 << 19) /* reserved bits should be 0 */
#define BPB_FSVER_OK (1 << 20) /* must be 0 */
#define BPB_ROOTCLUSTER_OK (1 << 21) /* must be != 0 and valid */
#define BPB_FSISEC_OK (1 << 22) /* != 0, <= reserved */
#define BPB_BKBOOTSEC_OK (1 << 23) /* != 0, <= reserved, != fsi */
#define BPB_VOLLAB16_OK (1 << 24) /* passes pc_validchar() */
#define BPB_VOLLAB32_OK (1 << 25) /* passes pc_validchar() */
#define BPB_NCLUSTERS_OK (1 << 26) /* from FAT spec */
#define BPB_CLSIZE_OK (1 << 27) /* cluster size */
#define BPB_MEDIASZ_OK (1 << 28) /* filesystem fits on device */
#define FAT12_VALIDMSK \
(BPB_SECSIZE_OK | BPB_SECPERCLUS_OK | BPB_CLSIZE_OK | \
BPB_RSVDSECCNT_OK | BPB_NUMFAT_OK | BPB_ROOTENTCNT_OK | \
BPB_TOTSEC_OK | BPB_TOTSEC16_OK | \
BPB_FATSZ_OK | BPB_FATSZ16_OK | BPB_BPBSIG_OK)
#define FAT16_VALIDMSK \
(BPB_SECSIZE_OK | BPB_SECPERCLUS_OK | BPB_CLSIZE_OK | \
BPB_RSVDSECCNT_OK | BPB_NUMFAT_OK | BPB_ROOTENTCNT_OK | \
BPB_TOTSEC_OK | BPB_TOTSEC16_OK | BPB_TOTSEC32_OK | \
BPB_FATSZ_OK | BPB_FATSZ16_OK | BPB_BPBSIG_OK)
/*
* A note on FAT32: According to the FAT spec, FAT32 _must_ have a valid
* extended BPB and therefore, as a proof of its existance, the FAT32
* boot signature (offset 66) must be valid as well. Why don't we check
* for BPB_BOOTSIG32_OK then ?
*
* We don't test for this here first-pass, because there are media out
* there that are valid FAT32 structurally but don't have a valid sig.
* This happens if older versions of the SYSLINUX bootloader (below 3.x)
* are installed on a media with a FAT32 on it. SYSLINUX 2.x and lower
* overwrite the BPB past the end of the FAT12/16 extension with its
* bootloader code - and the FAT16 extended BPB is 62 Bytes...
* All structurally relevant fields of the FAT32 BPB are within the first
* 52 Bytes, so the filesystem is accessible - but the signature check
* would reject it.
*/
#define FAT32_VALIDMSK \
(BPB_SECSIZE_OK | BPB_SECPERCLUS_OK | BPB_CLSIZE_OK | \
BPB_RSVDSECCNT_OK | BPB_NUMFAT_OK | BPB_ROOTENTCNT_OK | \
BPB_TOTSEC_OK | BPB_TOTSEC16_OK | BPB_TOTSEC32_OK | \
BPB_FATSZ_OK | BPB_FATSZ16_OK | BPB_FATSZ32_OK | \
BPB_EXTFLAGS_OK | BPB_FSVER_OK | BPB_ROOTCLUSTER_OK | \
BPB_BPBSIG_OK)
/*
* FAT32 BPB allows 'versioning' via FSVer32. We follow the 'NULL' spec.
*/
#define PCFS_SUPPORTED_FSVER 0
/*
* Filesystem summary information (introduced originally for FAT32 volumes).
* We need to maintain fs_free_clusters or Microsoft Scandisk will be upset.
* We keep these values in-core even for FAT12/FAT16 but will never attempt
* to write them out to disk then.
*/
typedef struct fat_fsinfo {
uint32_t fs_free_clusters; /* # free clusters. -1 if unknown */
uint32_t fs_next_free; /* search next free after this cn */
} fat_fsi_t;
/*
* On-disk FSI. All values in little endian. Only FAT32 has this.
*/
typedef struct fat_od_fsi {
uint32_t fsi_leadsig; /* 0x41615252 */
char fsi_reserved1[480];
uint32_t fsi_strucsig; /* 0x61417272 */
fat_fsi_t fsi_incore; /* free/nextfree */
char fsi_reserved2[12];
uint32_t fsi_trailsig; /* 0xaa550000 */
} fat_od_fsi_t;
#define FSI_LEADSIG LE_32(0x41615252)
#define FSI_STRUCSIG LE_32(0x61417272)
#define FSI_TRAILSIG LE_32(0xaa550000) /* same as MBB_MAGIC */
#define FSISIG_OK(fsi) ( \
((fat_od_fsi_t *)(fsi))->fsi_leadsig == FSI_LEADSIG && \
((fat_od_fsi_t *)(fsi))->fsi_strucsig == FSI_STRUCSIG && \
((fat_od_fsi_t *)(fsi))->fsi_trailsig == FSI_TRAILSIG)
#define FSINFO_UNKNOWN ((uint32_t)(-1)) /* free/next not valid */
typedef enum { FAT12, FAT16, FAT32, FAT_UNKNOWN, FAT_QUESTIONABLE } fattype_t;
struct pcfs {
struct vfs *pcfs_vfs; /* vfs for this fs */
int pcfs_flags; /* flags */
int pcfs_ldrive; /* logical DOS drive number */
fattype_t pcfs_fattype;
dev_t pcfs_xdev; /* actual device that is mounted */
struct vnode *pcfs_devvp; /* and a vnode for it */
int pcfs_secsize; /* sector size in bytes */
int pcfs_spcl; /* sectors per cluster */
int pcfs_spt; /* sectors per track */
int pcfs_sdshift; /* shift to convert sector into */
/* DEV_BSIZE "sectors"; assume */
/* pcfs_secsize is 2**n times of */
/* DEV_BSIZE */
int pcfs_fatsec; /* number of sec per FAT */
int pcfs_numfat; /* number of FAT copies */
int pcfs_rdirsec; /* number of sec in root dir */
daddr_t pcfs_dosstart; /* start blkno of DOS partition */
daddr_t pcfs_fsistart; /* start blkno of FSI sector */
daddr_t pcfs_fatstart; /* start blkno of first FAT */
daddr_t pcfs_rdirstart; /* start blkno of root dir */
daddr_t pcfs_datastart; /* start blkno of data area */
int pcfs_clsize; /* cluster size in bytes */
int pcfs_ncluster; /* number of clusters in fs */
int pcfs_nrefs; /* number of active pcnodes */
int pcfs_frefs; /* number of active file pcnodes */
int pcfs_nxfrecls; /* next free cluster */
uchar_t *pcfs_fatp; /* ptr to FAT data */
uchar_t *pcfs_fat_changemap; /* map of changed fat data */
int pcfs_fat_changemapsize; /* size of FAT changemap */
time_t pcfs_fattime; /* time FAT becomes invalid */
time_t pcfs_verifytime; /* time to reverify disk */
kmutex_t pcfs_lock; /* per filesystem lock */
kthread_id_t pcfs_owner; /* id of thread locking pcfs */
int pcfs_count; /* # of pcfs locks for pcfs_owner */
struct fat_fsinfo pcfs_fsinfo; /* in-core fsinfo */
struct pcfs *pcfs_nxt; /* linked list of all mounts */
int pcfs_fatjustread; /* Used to flag a freshly found FAT */
struct vnode *pcfs_root; /* vnode for the root dir of the fs */
int pcfs_secondswest; /* recording timezone for this fs */
len_t pcfs_mediasize;
int pcfs_rootblksize;
int pcfs_mediadesc; /* media descriptor */
pc_cluster32_t pcfs_lastclmark;
pc_cluster32_t pcfs_rootclnum;
timestruc_t pcfs_mounttime; /* timestamp for "/" */
};
/*
* flags
*/
#define PCFS_FATMOD 0x01 /* FAT has been modified */
#define PCFS_LOCKED 0x02 /* fs is locked */
#define PCFS_WANTED 0x04 /* locked fs is wanted */
#define PCFS_NOCHK 0x800 /* don't resync fat on error */
#define PCFS_BOOTPART 0x1000 /* boot partition type */
#define PCFS_HIDDEN 0x2000 /* show hidden files */
#define PCFS_PCMCIA_NO_CIS 0x4000 /* PCMCIA psuedo floppy */
#define PCFS_FOLDCASE 0x8000 /* fold filenames to lowercase */
#define PCFS_FSINFO_OK 0x10000 /* valid FAT32 fsinfo sector */
#define PCFS_IRRECOV 0x20000 /* FS was messed with during write */
#define PCFS_NOCLAMPTIME 0x40000 /* expose full FAT timestamp range */
#define PCFS_NOATIME 0x80000 /* disable atime updates */
#define IS_FAT12(PCFS) ((PCFS)->pcfs_fattype == FAT12)
#define IS_FAT16(PCFS) ((PCFS)->pcfs_fattype == FAT16)
#define IS_FAT32(PCFS) ((PCFS)->pcfs_fattype == FAT32)
/* for compatibility */
struct old_pcfs_args {
int secondswest; /* seconds west of Greenwich */
int dsttime; /* type of dst correction */
};
struct pcfs_args {
int secondswest; /* seconds west of Greenwich */
int dsttime; /* type of dst correction */
int flags;
};
/*
* pcfs mount options.
*/
#define MNTOPT_PCFS_HIDDEN "hidden"
#define MNTOPT_PCFS_NOHIDDEN "nohidden"
#define MNTOPT_PCFS_FOLDCASE "foldcase"
#define MNTOPT_PCFS_NOFOLDCASE "nofoldcase"
#define MNTOPT_PCFS_CLAMPTIME "clamptime"
#define MNTOPT_PCFS_NOCLAMPTIME "noclamptime"
#define MNTOPT_PCFS_TIMEZONE "timezone"
#define MNTOPT_PCFS_SECSIZE "secsize"
/*
* Disk timeout value in sec.
* This is used to time out the in core FAT and to re-verify the disk.
* This should be less than the time it takes to change floppys
*/
#define PCFS_DISKTIMEOUT 2
#define PCFS_MAXOFFSET_T UINT32_MAX /* PCFS max file size */
#define VFSTOPCFS(VFSP) ((struct pcfs *)((VFSP)->vfs_data))
#define PCFSTOVFS(FSP) ((FSP)->pcfs_vfs)
/*
* special cluster numbers in FAT
*/
#define PCF_FREECLUSTER 0x00 /* cluster is available */
#define PCF_ERRORCLUSTER 0x01 /* error occurred allocating cluster */
#define PCF_12BCLUSTER 0xFF0 /* 12-bit version of reserved cluster */
#define PCF_RESCLUSTER 0xFFF0 /* 16-bit version of reserved cluster */
#define PCF_RESCLUSTER32 0xFFFFFF0 /* 32-bit version */
#define PCF_BADCLUSTER 0xFFF7 /* bad cluster, do not use */
#define PCF_BADCLUSTER32 0xFFFFFF7 /* 32-bit version */
#define PCF_LASTCLUSTER 0xFFF8 /* >= means last cluster in file */
#define PCF_LASTCLUSTER32 0xFFFFFF8 /* 32-bit version */
#define PCF_LASTCLUSTERMARK 0xFFFF /* value used to mark last cluster */
#define PCF_LASTCLUSTERMARK32 0xFFFFFFF /* 32-bit version */
#define PCF_FIRSTCLUSTER 2 /* first valid cluster number */
/*
* file system constants
*/
#define PC_MAXFATSEC 256 /* maximum number of sectors in FAT */
/*
* file system parameter macros
*/
#define pc_clear_fatchanges(PCFS) \
bzero((PCFS)->pcfs_fat_changemap, (PCFS)->pcfs_fat_changemapsize)
#define pc_blksize(PCFS, PCP, OFF) /* file system block size */ \
(((PCTOV(PCP)->v_flag & VROOT) && !IS_FAT32(PCFS)) ? \
((OFF) >= \
((PCFS)->pcfs_rdirsec & \
~((PCFS)->pcfs_spcl - 1)) * ((PCFS)->pcfs_secsize)? \
((PCFS)->pcfs_rdirsec & \
((PCFS)->pcfs_spcl - 1)) * ((PCFS)->pcfs_secsize): \
(PCFS)->pcfs_clsize): \
(PCFS)->pcfs_clsize)
#define pc_blkoff(PCFS, OFF) /* offset within block */ \
((int)((OFF) & ((PCFS)->pcfs_clsize - 1)))
#define pc_lblkno(PCFS, OFF) /* logical block (cluster) no */ \
((daddr_t)((OFF) / (PCFS)->pcfs_clsize))
#define pc_dbtocl(PCFS, DB) /* disk blks to clusters */ \
((int)((DB) / (PCFS)->pcfs_spcl))
#define pc_cltodb(PCFS, CL) /* clusters to disk blks */ \
((daddr_t)((CL) * (PCFS)->pcfs_spcl))
#define pc_dbdaddr(PCFS, DB) /* sector to DEV_BSIZE "sector" addr */ \
((DB) << (PCFS)->pcfs_sdshift)
#define pc_daddrdb(PCFS, DADDR) /* DEV_BSIZE "sector" addr to sector addr */ \
((DADDR) >> (PCFS)->pcfs_sdshift)
#define pc_cldaddr(PCFS, CL) /* DEV_BSIZE "sector" addr for cluster */ \
pc_dbdaddr(PCFS, ((daddr_t)((PCFS)->pcfs_datastart + \
pc_cltodb(PCFS, (CL) - PCF_FIRSTCLUSTER))))
#define pc_daddrcl(PCFS, DADDR) /* cluster for disk address */ \
((int)(PCF_FIRSTCLUSTER + \
pc_dbtocl(pc_daddrdb(PCFS, DADDR) - (PCFS)->pcfs_datastart)))
/*
* Number of directory entries per sector / cluster
*/
#define pc_direntpersec(PCFS) \
((int)((PCFS)->pcfs_secsize / sizeof (struct pcdir)))
#define pc_direntpercl(PCFS) \
((int)((PCFS)->pcfs_clsize / sizeof (struct pcdir)))
/*
* out-of-range check for cluster numbers.
*/
#define pc_validcl(PCFS, CL) /* check that cluster no is legit */ \
((int)(CL) >= PCF_FIRSTCLUSTER && \
(int)(CL) < (PCFS)->pcfs_ncluster + PCF_FIRSTCLUSTER)
/*
* external routines.
*/
extern int pc_lockfs(struct pcfs *, int, int); /* lock fs and get fat */
extern void pc_unlockfs(struct pcfs *); /* ulock the fs */
extern int pc_getfat(struct pcfs *); /* get fat from disk */
extern void pc_invalfat(struct pcfs *); /* invalidate incore fat */
extern int pc_syncfat(struct pcfs *); /* sync fat to disk */
extern int pc_freeclusters(struct pcfs *); /* num free clusters in fs */
extern pc_cluster32_t pc_alloccluster(struct pcfs *, int);
extern void pc_setcluster(struct pcfs *, pc_cluster32_t, pc_cluster32_t);
extern void pc_mark_fat_updated(struct pcfs *fsp, pc_cluster32_t cn);
extern int pc_fat_is_changed(struct pcfs *fsp, pc_cluster32_t bn);
/*
* debugging
*/
extern int pcfsdebuglevel;
#define PC_DPRINTF0(level, A) \
if (pcfsdebuglevel >= level) \
cmn_err(CE_CONT, (A))
#define PC_DPRINTF1(level, A, B) \
if (pcfsdebuglevel >= level) \
cmn_err(CE_CONT, (A), (B))
#define PC_DPRINTF2(level, A, B, C) \
if (pcfsdebuglevel >= level) \
cmn_err(CE_CONT, (A), (B), (C))
#define PC_DPRINTF3(level, A, B, C, D) \
if (pcfsdebuglevel >= level) \
cmn_err(CE_CONT, (A), (B), (C), (D))
#define PC_DPRINTF4(level, A, B, C, D, E) \
if (pcfsdebuglevel >= level) \
cmn_err(CE_CONT, (A), (B), (C), (D), (E))
#ifdef __cplusplus
}
#endif
#endif /* _SYS_FS_PC_FS_H */
|