Home | History | Annotate | Download | only in fs
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #ifndef	_SYS_FS_PC_FS_H
     27 #define	_SYS_FS_PC_FS_H
     28 
     29 #include <sys/thread.h>
     30 #include <sys/ksynch.h>
     31 #include <sys/sysmacros.h>
     32 #include <sys/byteorder.h>
     33 
     34 #ifdef	__cplusplus
     35 extern "C" {
     36 #endif
     37 
     38 typedef	uint16_t	pc_cluster16_t;
     39 typedef	uint32_t	pc_cluster32_t;
     40 
     41 /*
     42  * PC (MSDOS) compatible virtual file system.
     43  *
     44  * A main goal of the implementation was to maintain statelessness
     45  * except while files are open. Thus mounting and unmounting merely
     46  * declared the file system name. The user may change disks at almost
     47  * any time without concern (just like the PC). It is assumed that when
     48  * files are open for writing the disk access light will be on, as a
     49  * warning not to change disks. The implementation must, however, detect
     50  * disk change and recover gracefully. It does this by comparing the
     51  * in core entry for a directory to the on disk entry whenever a directory
     52  * is searched. If a discrepancy is found active directories become root and
     53  * active files are marked invalid.
     54  *
     55  * There are only two type of nodes on the PC file system; files and
     56  * directories. These are represented by two separate vnode op vectors,
     57  * and they are kept in two separate tables. Files are known by the
     58  * disk block number and block (cluster) offset of the files directory
     59  * entry. Directories are known by the starting cluster number.
     60  *
     61  * The file system is locked for during each user operation. This is
     62  * done to simplify disk verification error conditions.
     63  *
     64  * Notes on FAT32 support
     65  * ----------------------
     66  * The basic difference between FAT32 and FAT16 is that cluster numbers are now
     67  * 32-bit instead of 16-bit. The FAT is thus an array of 32-bit cluster numbers,
     68  * and because of this the cluster size can be much smaller on a large disk
     69  * (4k, say, on a 1 Gig drive instead of 16k). Unfortunately, the FAT is not
     70  * the only place cluster numbers are stored - the starting cluster is stored
     71  * in the directory entry for a file, and of course it's only 16-bit. Luckily,
     72  * there's a 16-bit OS/2 Extended Attribute field that is now used to store the
     73  * upper 16-bits of the starting cluster number.
     74  *
     75  * Most of the FAT32 changes to pcfs are under 'if it's FAT32' to minimize the
     76  * effect on non-FAT32 filesystems (and still share the code), except for the
     77  * starting cluster changes. It seemed easier to make common functions to
     78  * handle that.
     79  *
     80  * Other changes:
     81  *
     82  *     1. FAT32 partitions are indicated by partition types 0xB and 0xC.
     83  *     2. The boot sector is now 2 sectors, to make room for FAT32 extensions.
     84  *     3. The root directory is no longer stored in a fixed location. Its'
     85  *        starting cluster is stored in the extended boot sector.
     86  *     4. "Summary information" is now stored and we need to (at least) maintain
     87  *        the number of free clusters or scandisk will be upset. Though the
     88  *        sector this info is in is pointed to by the extensions in the boot
     89  *        sector, the magic offset of this information is just that so
     90  *        far - magic. 0x1e0.
     91  *     5. FAT32 can use the alternate FAT. But we don't.
     92  *
     93  * FAT32 also exposed a latent bug: we bread() each copy of the FAT in one
     94  * big chunk.  This is not good on a large FAT32 drive, such as a 1 Gig
     95  * Jaz drive that has 4k clusters, since the FAT becomes 1 Meg in size and
     96  * bread blocks forever. So now we read the FAT in chunks.
     97  */
     98 
     99 
    100 /*
    101  * The FAT bootsector uses little-endian multibyte values not aligned at
    102  * a 'native' wordsize. Instead of defining a strange data structure and
    103  * odd accessor methods for some members while using standard C accesses
    104  * for others, we don't bother and just define the structure offsets, and
    105  * a common set of misaligned-littleendian accessor macros.
    106  *
    107  * The "bootsec" and "fat32_bootsec" structures are only provided for
    108  * compatibility with old code including <sys/fs/pc_fs.h> but not used
    109  * by the PCFS kernel driver anymore.
    110  */
    111 struct bootsec {
    112 	uchar_t	instr[3];
    113 	uchar_t	version[8];
    114 	uchar_t	bps[2];			/* bytes per sector */
    115 	uchar_t	spcl;			/* sectors per allocation unit */
    116 	uchar_t	res_sec[2];		/* reserved sectors, starting at 0 */
    117 	uchar_t	nfat;			/* number of FATs */
    118 	uchar_t	rdirents[2];		/* number of root directory entries */
    119 	uchar_t	numsect[2];		/* old total sectors in logical image */
    120 	uchar_t	mediadesriptor;		/* media descriptor byte */
    121 	ushort_t fatsec;		/* number of sectors per FAT */
    122 	ushort_t spt;			/* sectors per track */
    123 	ushort_t nhead;			/* number of heads */
    124 	uint_t	hiddensec;		/* number of hidden sectors */
    125 	uint_t	totalsec;		/* total sectors in logical image */
    126 };
    127 
    128 /*
    129  * FAT32 volumes have a bigger boot sector. They include the normal
    130  * boot sector.
    131  */
    132 struct fat32_bootsec {
    133 	struct bootsec	f_bs;
    134 	uint32_t	f_fatlength;	/* size of FAT */
    135 	uint16_t	f_flags;
    136 	uint8_t		f_major;	/* major filesystem version #? */
    137 	uint8_t		f_minor;	/* minor filesystem version #? */
    138 	uint32_t	f_rootcluster;	/* first cluster in root directory */
    139 	uint16_t	f_infosector;	/* where summary info is */
    140 	uint16_t	f_backupboot;	/* backup boot sector */
    141 	uint16_t	f_reserved2[6];
    142 };
    143 
    144 
    145 #define	OFF_JMPBOOT	0
    146 #define	OFF_OEMNAME	3
    147 #define	OFF_BYTESPERSEC	11
    148 #define	OFF_SECPERCLUS	13
    149 #define	OFF_RSVDSECCNT	14
    150 #define	OFF_NUMFATS	16
    151 #define	OFF_ROOTENTCNT	17
    152 #define	OFF_TOTSEC16	19
    153 #define	OFF_MEDIA	21
    154 #define	OFF_FATSZ16	22
    155 #define	OFF_SECPERTRK	24
    156 #define	OFF_NUMHEADS	26
    157 #define	OFF_HIDDSEC	28
    158 #define	OFF_TOTSEC32	32
    159 #define	OFF_BPBSIG	510
    160 
    161 #define	OFF_DRVNUM16	36
    162 #define	OFF_BOOTSIG16	38
    163 #define	OFF_VOLID16	39
    164 #define	OFF_VOLLAB16	43
    165 #define	OFF_FILSYSTYP16	54
    166 
    167 #define	OFF_FATSZ32	36
    168 #define	OFF_EXTFLAGS32	40
    169 #define	OFF_FSVER32	42
    170 #define	OFF_ROOTCLUS32	44
    171 #define	OFF_FSINFO32	48
    172 #define	OFF_BKBOOTSEC32	50
    173 #define	OFF_DRVNUM32	64
    174 #define	OFF_BOOTSIG32	66
    175 #define	OFF_VOLID32	67
    176 #define	OFF_VOLLAB32	71
    177 #define	OFF_FILSYSTYP32	82
    178 
    179 #define	LE_16_NA(addr)					\
    180 	(((uint16_t)*((uint8_t *)(addr))) +		\
    181 	((uint16_t)*((uint8_t *)(addr) + 1) << 8))
    182 
    183 #define	LE_32_NA(addr)					\
    184 	(((uint32_t)*((uint8_t *)(addr))) +		\
    185 	((uint32_t)*((uint8_t *)(addr) + 1) << 8) +	\
    186 	((uint32_t)*((uint8_t *)(addr) + 2) << 16) +	\
    187 	((uint32_t)*((uint8_t *)(addr) + 3) << 24))
    188 
    189 /*
    190  * Generic FAT BPB fields
    191  */
    192 #define	bpb_jmpBoot(bpb)		((unsigned char *)(bpb))
    193 #define	bpb_OEMName(bpb)		((char *)(bpb) + OFF_OEMNAME)
    194 #define	bpb_get_BytesPerSec(bpb)	LE_16_NA((bpb) + OFF_BYTESPERSEC)
    195 #define	bpb_get_SecPerClus(bpb)		(((uint8_t *)(bpb))[OFF_SECPERCLUS])
    196 #define	bpb_get_RsvdSecCnt(bpb)		LE_16_NA((bpb) + OFF_RSVDSECCNT)
    197 #define	bpb_get_NumFATs(bpb)		(((uint8_t *)(bpb))[OFF_NUMFATS])
    198 #define	bpb_get_RootEntCnt(bpb)		LE_16_NA((bpb) + OFF_ROOTENTCNT)
    199 #define	bpb_get_TotSec16(bpb)		LE_16_NA((bpb) + OFF_TOTSEC16)
    200 #define	bpb_get_Media(bpb)		(((uint8_t *)(bpb))[OFF_MEDIA])
    201 #define	bpb_get_FatSz16(bpb)		LE_16_NA((bpb) + OFF_FATSZ16)
    202 #define	bpb_get_SecPerTrk(bpb)		LE_16_NA((bpb) + OFF_SECPERTRK)
    203 #define	bpb_get_NumHeads(bpb)		LE_16_NA((bpb) + OFF_NUMHEADS)
    204 #define	bpb_get_HiddSec(bpb)		LE_32_NA((bpb) + OFF_HIDDSEC)
    205 #define	bpb_get_TotSec32(bpb)		LE_32_NA((bpb) + OFF_TOTSEC32)
    206 #define	bpb_get_BPBSig(bpb)		LE_16_NA((bpb) + OFF_BPBSIG)
    207 
    208 /*
    209  * FAT12/16 extended BPB fields
    210  */
    211 #define	bpb_get_DrvNum16(bpb)		(((uint8_t *)(bpb))[OFF_DRVNUM16])
    212 #define	bpb_get_BootSig16(bpb)		(((uint8_t *)(bpb))[OFF_BOOTSIG16])
    213 #define	bpb_VolLab16(bpb)		((char *)(bpb) + OFF_VOLLAB16)
    214 #define	bpb_FilSysType16(bpb)		((char *)(bpb) + OFF_FILSYSTYP16)
    215 #define	bpb_get_VolID16(bpb)		LE_32_NA((bpb) + OFF_VOLID16)
    216 
    217 /*
    218  * FAT32 extended BPB fields
    219  */
    220 #define	bpb_get_FatSz32(bpb)		LE_32_NA((bpb) + OFF_FATSZ32)
    221 #define	bpb_get_ExtFlags32(bpb)		LE_16_NA((bpb) + OFF_EXTFLAGS32)
    222 #define	bpb_get_FSVer32(bpb)		LE_16_NA((bpb) + OFF_FSVER32)
    223 #define	bpb_get_RootClus32(bpb)		LE_32_NA((bpb) + OFF_ROOTCLUS32)
    224 #define	bpb_get_FSInfo32(bpb)		LE_16_NA((bpb) + OFF_FSINFO32)
    225 #define	bpb_get_BkBootSec32(bpb)	LE_16_NA((bpb) + OFF_BKBOOTSEC32)
    226 #define	bpb_get_DrvNum32(bpb)		(((uint8_t *)(bpb))[OFF_DRVNUM32])
    227 #define	bpb_get_BootSig32(bpb)		(((uint8_t *)(bpb))[OFF_BOOTSIG32])
    228 #define	bpb_get_VolID32(bpb)		LE_32_NA((bpb) + OFF_VOLID32)
    229 #define	bpb_VolLab32(bpb)		((char *)(bpb) + OFF_VOLLAB32)
    230 #define	bpb_FilSysType32(bpb)		((char *)(bpb) + OFF_FILSYSTYP32)
    231 
    232 /*
    233  * Validators
    234  */
    235 #define	VALID_SECSIZE(s)	\
    236 	(s == 512 || s == 1024 || s == 2048 || s == 4096)
    237 #define	VALID_SPCL(s)		(ISP2((s)) && (unsigned int)(s) <= 128)
    238 #define	VALID_CLSIZE(s)		(ISP2((s)) && (unsigned int)(s) <= (64 * 1024))
    239 #define	VALID_NUMFATS(n)	((n) > 0 && (n) < 8)
    240 #define	VALID_RSVDSEC(s)	((s) > 0)
    241 #define	VALID_BPBSIG(sig)	((sig) == MBB_MAGIC)
    242 #define	VALID_BOOTSIG(sig)	((sig) == 0x29)
    243 #define	VALID_MEDIA(m)		((m) == 0xF0 || ((m) >= 0xF8 && (m) <= 0xFF))
    244 
    245 /*
    246  * this might require a change for codepage support. In particular,
    247  * pc_validchar() cannot be a macro anymore if codepages get involved.
    248  */
    249 #define	VALID_VOLLAB(l)		(			\
    250 	pc_validchar((l)[0]) && pc_validchar((l)[1]) && \
    251 	pc_validchar((l)[2]) &&	pc_validchar((l)[3]) && \
    252 	pc_validchar((l)[4]) && pc_validchar((l)[5]) && \
    253 	pc_validchar((l)[6]) && pc_validchar((l)[7]) && \
    254 	pc_validchar((l)[8]) && pc_validchar((l)[9]) && \
    255 	pc_validchar((l)[10]))
    256 
    257 /*
    258  * We might actually use the 'validchar' checks as well; it only needs
    259  * to be printable. Should this ever caused failed media recognition,
    260  * we can change it. Many ISVs put different strings into the "oemname"
    261  * field.
    262  */
    263 #define	VALID_OEMNAME(nm)	(			\
    264 	bcmp((nm), "MSDOS", 5) == 0 || bcmp((nm), "MSWIN", 5) == 0)
    265 #define	VALID_FSTYPSTR16(typ)	(bcmp((typ), "FAT", 3) == 0)
    266 #define	VALID_FSTYPSTR32(typ)	(bcmp((typ), "FAT32", 5) == 0)
    267 #define	VALID_JMPBOOT(b)	(			\
    268 	((b)[0] == 0xeb && (b)[2] == 0x90) || (b)[0] == 0xe9)
    269 #define	VALID_FSVER32(v)	((v) == PCFS_SUPPORTED_FSVER)
    270 /*
    271  * Can we check this properly somehow ? There should be a better way.
    272  * The FAT spec doesn't mention reserved bits need to be zero ...
    273  */
    274 #define	VALID_EXTFLAGS(flags)	(((flags) & 0x8f) == (flags))
    275 
    276 /*
    277  * Validation results
    278  */
    279 #define	BPB_SECSIZE_OK		(1 << 0)	/* ok: 512/1024/2048/4096 */
    280 #define	BPB_OEMNAME_OK		(1 << 1)	/* "MSDOS" or "MSWIN" */
    281 #define	BPB_JMPBOOT_OK		(1 << 2)	/* 16bit "jmp" / "call" */
    282 #define	BPB_SECPERCLUS_OK	(1 << 3)	/* power of 2, [1 .. 128] */
    283 #define	BPB_RSVDSECCNT_OK	(1 << 4)	/* cannot be zero */
    284 #define	BPB_NUMFAT_OK		(1 << 5)	/* >= 1, <= 8 */
    285 #define	BPB_ROOTENTCNT_OK	(1 << 6)	/* 0 on FAT32, != 0 else */
    286 #define	BPB_TOTSEC_OK		(1 << 7)	/* smaller than volume */
    287 #define	BPB_TOTSEC16_OK		(1 << 8)	/* 0 on FAT32, != 0 on FAT12 */
    288 #define	BPB_TOTSEC32_OK		(1 << 9)	/* 0 on FAT12, != 0 on FAT32 */
    289 #define	BPB_MEDIADESC_OK	(1 << 10)	/* 0xf0 or 0xf8..0xff */
    290 #define	BPB_FATSZ_OK		(1 << 11)	/* [nclusters], no smaller */
    291 #define	BPB_FATSZ16_OK		(1 << 12)	/* 0 on FAT32, != 0 else */
    292 #define	BPB_FATSZ32_OK		(1 << 13)	/* non-zero on FAT32 */
    293 #define	BPB_BPBSIG_OK		(1 << 14)	/* 0x55, 0xAA */
    294 #define	BPB_BOOTSIG16_OK	(1 << 15)	/* 0x29 - if present */
    295 #define	BPB_BOOTSIG32_OK	(1 << 16)	/* 0x29 - unless SYSLINUX2.x */
    296 #define	BPB_FSTYPSTR16_OK	(1 << 17)	/* At least "FAT" */
    297 #define	BPB_FSTYPSTR32_OK	(1 << 18)	/* "FAT32" */
    298 #define	BPB_EXTFLAGS_OK		(1 << 19)	/* reserved bits should be 0 */
    299 #define	BPB_FSVER_OK		(1 << 20)	/* must be 0 */
    300 #define	BPB_ROOTCLUSTER_OK	(1 << 21)	/* must be != 0 and valid */
    301 #define	BPB_FSISEC_OK		(1 << 22)	/* != 0, <= reserved */
    302 #define	BPB_BKBOOTSEC_OK	(1 << 23)	/* != 0, <= reserved, != fsi */
    303 #define	BPB_VOLLAB16_OK		(1 << 24)	/* passes pc_validchar() */
    304 #define	BPB_VOLLAB32_OK		(1 << 25)	/* passes pc_validchar() */
    305 #define	BPB_NCLUSTERS_OK	(1 << 26)	/* from FAT spec */
    306 #define	BPB_CLSIZE_OK		(1 << 27)	/* cluster size */
    307 #define	BPB_MEDIASZ_OK		(1 << 28)	/* filesystem fits on device */
    308 
    309 #define	FAT12_VALIDMSK							\
    310 	(BPB_SECSIZE_OK | BPB_SECPERCLUS_OK | BPB_CLSIZE_OK |		\
    311 	BPB_RSVDSECCNT_OK | BPB_NUMFAT_OK | BPB_ROOTENTCNT_OK |		\
    312 	BPB_TOTSEC_OK | BPB_TOTSEC16_OK |				\
    313 	BPB_FATSZ_OK | BPB_FATSZ16_OK |	BPB_BPBSIG_OK)
    314 
    315 #define	FAT16_VALIDMSK							\
    316 	(BPB_SECSIZE_OK | BPB_SECPERCLUS_OK | BPB_CLSIZE_OK |		\
    317 	BPB_RSVDSECCNT_OK | BPB_NUMFAT_OK | BPB_ROOTENTCNT_OK |		\
    318 	BPB_TOTSEC_OK | BPB_TOTSEC16_OK | BPB_TOTSEC32_OK | 		\
    319 	BPB_FATSZ_OK | BPB_FATSZ16_OK | BPB_BPBSIG_OK)
    320 
    321 /*
    322  * A note on FAT32: According to the FAT spec, FAT32 _must_ have a valid
    323  * extended BPB and therefore, as a proof of its existance, the FAT32
    324  * boot signature (offset 66) must be valid as well. Why don't we check
    325  * for BPB_BOOTSIG32_OK  then ?
    326  *
    327  * We don't test for this here first-pass, because there are media out
    328  * there that are valid FAT32 structurally but don't have a valid sig.
    329  * This happens if older versions of the SYSLINUX bootloader (below 3.x)
    330  * are installed on a media with a FAT32 on it. SYSLINUX 2.x and lower
    331  * overwrite the BPB past the end of the FAT12/16 extension with its
    332  * bootloader code - and the FAT16 extended BPB is 62 Bytes...
    333  * All structurally relevant fields of the FAT32 BPB are within the first
    334  * 52 Bytes, so the filesystem is accessible - but the signature check
    335  * would reject it.
    336  */
    337 #define	FAT32_VALIDMSK							\
    338 	(BPB_SECSIZE_OK | BPB_SECPERCLUS_OK | BPB_CLSIZE_OK |		\
    339 	BPB_RSVDSECCNT_OK | BPB_NUMFAT_OK | BPB_ROOTENTCNT_OK |		\
    340 	BPB_TOTSEC_OK | BPB_TOTSEC16_OK | BPB_TOTSEC32_OK | 		\
    341 	BPB_FATSZ_OK | BPB_FATSZ16_OK |	BPB_FATSZ32_OK |		\
    342 	BPB_EXTFLAGS_OK | BPB_FSVER_OK | BPB_ROOTCLUSTER_OK |		\
    343 	BPB_BPBSIG_OK)
    344 
    345 /*
    346  * FAT32 BPB allows 'versioning' via FSVer32. We follow the 'NULL' spec.
    347  */
    348 #define	PCFS_SUPPORTED_FSVER	0
    349 
    350 
    351 /*
    352  * Filesystem summary information (introduced originally for FAT32 volumes).
    353  * We need to maintain fs_free_clusters or Microsoft Scandisk will be upset.
    354  * We keep these values in-core even for FAT12/FAT16 but will never attempt
    355  * to write them out to disk then.
    356  */
    357 typedef struct fat_fsinfo {
    358 	uint32_t fs_free_clusters;	/* # free clusters. -1 if unknown */
    359 	uint32_t fs_next_free;		/* search next free after this cn */
    360 } fat_fsi_t;
    361 
    362 /*
    363  * On-disk FSI. All values in little endian. Only FAT32 has this.
    364  */
    365 typedef struct fat_od_fsi {
    366 	uint32_t	fsi_leadsig;		/* 0x41615252 */
    367 	char		fsi_reserved1[480];
    368 	uint32_t	fsi_strucsig;		/* 0x61417272 */
    369 	fat_fsi_t	fsi_incore;		/* free/nextfree */
    370 	char		fsi_reserved2[12];
    371 	uint32_t	fsi_trailsig;		/* 0xaa550000 */
    372 } fat_od_fsi_t;
    373 
    374 #define	FSI_LEADSIG	LE_32(0x41615252)
    375 #define	FSI_STRUCSIG	LE_32(0x61417272)
    376 #define	FSI_TRAILSIG	LE_32(0xaa550000)	/* same as MBB_MAGIC */
    377 
    378 #define	FSISIG_OK(fsi)	(						\
    379 	((fat_od_fsi_t *)(fsi))->fsi_leadsig == FSI_LEADSIG &&		\
    380 	((fat_od_fsi_t *)(fsi))->fsi_strucsig == FSI_STRUCSIG &&	\
    381 	((fat_od_fsi_t *)(fsi))->fsi_trailsig == FSI_TRAILSIG)
    382 
    383 #define	FSINFO_UNKNOWN	((uint32_t)(-1))	/* free/next not valid */
    384 
    385 typedef enum { FAT12, FAT16, FAT32, FAT_UNKNOWN, FAT_QUESTIONABLE } fattype_t;
    386 
    387 
    388 struct pcfs {
    389 	struct vfs *pcfs_vfs;		/* vfs for this fs */
    390 	int pcfs_flags;			/* flags */
    391 	int pcfs_ldrive;		/* logical DOS drive number */
    392 	fattype_t pcfs_fattype;
    393 	dev_t pcfs_xdev;		/* actual device that is mounted */
    394 	struct vnode *pcfs_devvp;	/*   and a vnode for it */
    395 	int pcfs_secsize;		/* sector size in bytes */
    396 	int pcfs_spcl;			/* sectors per cluster */
    397 	int pcfs_spt;			/* sectors per track */
    398 	int pcfs_sdshift;		/* shift to convert sector into */
    399 					/* DEV_BSIZE "sectors"; assume */
    400 					/* pcfs_secsize is 2**n times of */
    401 					/* DEV_BSIZE */
    402 	int pcfs_fatsec;		/* number of sec per FAT */
    403 	int pcfs_numfat;		/* number of FAT copies */
    404 	int pcfs_rdirsec;		/* number of sec in root dir */
    405 	daddr_t pcfs_dosstart;		/* start blkno of DOS partition */
    406 	daddr_t pcfs_fsistart;		/* start blkno of FSI sector */
    407 	daddr_t pcfs_fatstart;		/* start blkno of first FAT */
    408 	daddr_t pcfs_rdirstart;		/* start blkno of root dir */
    409 	daddr_t pcfs_datastart;		/* start blkno of data area */
    410 	int pcfs_clsize;		/* cluster size in bytes */
    411 	int pcfs_ncluster;		/* number of clusters in fs */
    412 	int pcfs_nrefs;			/* number of active pcnodes */
    413 	int pcfs_frefs;			/* number of active file pcnodes */
    414 	int pcfs_nxfrecls;		/* next free cluster */
    415 	uchar_t *pcfs_fatp;		/* ptr to FAT data */
    416 	uchar_t *pcfs_fat_changemap;	/* map of changed fat data */
    417 	int pcfs_fat_changemapsize;	/* size of FAT changemap */
    418 	time_t pcfs_fattime;		/* time FAT becomes invalid */
    419 	time_t pcfs_verifytime;		/* time to reverify disk */
    420 	kmutex_t	pcfs_lock;		/* per filesystem lock */
    421 	kthread_id_t pcfs_owner;		/* id of thread locking pcfs */
    422 	int pcfs_count;			/* # of pcfs locks for pcfs_owner */
    423 	struct fat_fsinfo pcfs_fsinfo;	/* in-core fsinfo */
    424 	struct pcfs *pcfs_nxt;		/* linked list of all mounts */
    425 	int pcfs_fatjustread;		/* Used to flag a freshly found FAT */
    426 	struct vnode *pcfs_root;	/* vnode for the root dir of the fs */
    427 	int pcfs_secondswest;		/* recording timezone for this fs */
    428 	len_t pcfs_mediasize;
    429 	int pcfs_rootblksize;
    430 	int pcfs_mediadesc;		/* media descriptor */
    431 	pc_cluster32_t pcfs_lastclmark;
    432 	pc_cluster32_t pcfs_rootclnum;
    433 	timestruc_t pcfs_mounttime;	/* timestamp for "/" */
    434 };
    435 
    436 /*
    437  * flags
    438  */
    439 #define	PCFS_FATMOD		0x01	/* FAT has been modified */
    440 #define	PCFS_LOCKED		0x02	/* fs is locked */
    441 #define	PCFS_WANTED		0x04	/* locked fs is wanted */
    442 #define	PCFS_NOCHK		0x800	/* don't resync fat on error */
    443 #define	PCFS_BOOTPART		0x1000	/* boot partition type */
    444 #define	PCFS_HIDDEN		0x2000	/* show hidden files */
    445 #define	PCFS_PCMCIA_NO_CIS	0x4000	/* PCMCIA psuedo floppy */
    446 #define	PCFS_FOLDCASE		0x8000	/* fold filenames to lowercase */
    447 #define	PCFS_FSINFO_OK		0x10000	/* valid FAT32 fsinfo sector */
    448 #define	PCFS_IRRECOV		0x20000	/* FS was messed with during write */
    449 #define	PCFS_NOCLAMPTIME	0x40000	/* expose full FAT timestamp range */
    450 #define	PCFS_NOATIME		0x80000	/* disable atime updates */
    451 
    452 #define	IS_FAT12(PCFS)	((PCFS)->pcfs_fattype == FAT12)
    453 #define	IS_FAT16(PCFS)	((PCFS)->pcfs_fattype == FAT16)
    454 #define	IS_FAT32(PCFS)	((PCFS)->pcfs_fattype == FAT32)
    455 
    456 /* for compatibility */
    457 struct old_pcfs_args {
    458 	int	secondswest;	/* seconds west of Greenwich */
    459 	int	dsttime;    	/* type of dst correction */
    460 };
    461 
    462 struct pcfs_args {
    463 	int	secondswest;	/* seconds west of Greenwich */
    464 	int	dsttime;    	/* type of dst correction */
    465 	int	flags;
    466 };
    467 
    468 /*
    469  * pcfs mount options.
    470  */
    471 #define	MNTOPT_PCFS_HIDDEN	"hidden"
    472 #define	MNTOPT_PCFS_NOHIDDEN	"nohidden"
    473 #define	MNTOPT_PCFS_FOLDCASE	"foldcase"
    474 #define	MNTOPT_PCFS_NOFOLDCASE	"nofoldcase"
    475 #define	MNTOPT_PCFS_CLAMPTIME	"clamptime"
    476 #define	MNTOPT_PCFS_NOCLAMPTIME	"noclamptime"
    477 #define	MNTOPT_PCFS_TIMEZONE	"timezone"
    478 #define	MNTOPT_PCFS_SECSIZE	"secsize"
    479 
    480 /*
    481  * Disk timeout value in sec.
    482  * This is used to time out the in core FAT and to re-verify the disk.
    483  * This should be less than the time it takes to change floppys
    484  */
    485 #define	PCFS_DISKTIMEOUT	2
    486 
    487 #define	PCFS_MAXOFFSET_T	UINT32_MAX	/* PCFS max file size */
    488 
    489 #define	VFSTOPCFS(VFSP)		((struct pcfs *)((VFSP)->vfs_data))
    490 #define	PCFSTOVFS(FSP)		((FSP)->pcfs_vfs)
    491 
    492 /*
    493  * special cluster numbers in FAT
    494  */
    495 #define	PCF_FREECLUSTER		0x00	/* cluster is available */
    496 #define	PCF_ERRORCLUSTER	0x01	/* error occurred allocating cluster */
    497 #define	PCF_12BCLUSTER		0xFF0	/* 12-bit version of reserved cluster */
    498 #define	PCF_RESCLUSTER		0xFFF0	/* 16-bit version of reserved cluster */
    499 #define	PCF_RESCLUSTER32	0xFFFFFF0 /* 32-bit version */
    500 #define	PCF_BADCLUSTER		0xFFF7	/* bad cluster, do not use */
    501 #define	PCF_BADCLUSTER32	0xFFFFFF7 /* 32-bit version */
    502 #define	PCF_LASTCLUSTER		0xFFF8	/* >= means last cluster in file */
    503 #define	PCF_LASTCLUSTER32	0xFFFFFF8 /* 32-bit version */
    504 #define	PCF_LASTCLUSTERMARK	0xFFFF	/* value used to mark last cluster */
    505 #define	PCF_LASTCLUSTERMARK32	0xFFFFFFF /* 32-bit version */
    506 #define	PCF_FIRSTCLUSTER	2	/* first valid cluster number */
    507 
    508 /*
    509  * file system constants
    510  */
    511 #define	PC_MAXFATSEC	256		/* maximum number of sectors in FAT */
    512 
    513 /*
    514  * file system parameter macros
    515  */
    516 
    517 #define	pc_clear_fatchanges(PCFS) \
    518 	bzero((PCFS)->pcfs_fat_changemap, (PCFS)->pcfs_fat_changemapsize)
    519 
    520 #define	pc_blksize(PCFS, PCP, OFF)	/* file system block size */	\
    521 	(((PCTOV(PCP)->v_flag & VROOT) && !IS_FAT32(PCFS)) ? \
    522 	    ((OFF) >= \
    523 	    ((PCFS)->pcfs_rdirsec & \
    524 	    ~((PCFS)->pcfs_spcl - 1)) * ((PCFS)->pcfs_secsize)? \
    525 	    ((PCFS)->pcfs_rdirsec & \
    526 	    ((PCFS)->pcfs_spcl - 1)) * ((PCFS)->pcfs_secsize): \
    527 	    (PCFS)->pcfs_clsize): \
    528 	    (PCFS)->pcfs_clsize)
    529 
    530 #define	pc_blkoff(PCFS, OFF)		/* offset within block */ \
    531 	((int)((OFF) & ((PCFS)->pcfs_clsize - 1)))
    532 
    533 #define	pc_lblkno(PCFS, OFF)		/* logical block (cluster) no */ \
    534 	((daddr_t)((OFF) / (PCFS)->pcfs_clsize))
    535 
    536 #define	pc_dbtocl(PCFS, DB)		/* disk blks to clusters */ \
    537 	((int)((DB) / (PCFS)->pcfs_spcl))
    538 
    539 #define	pc_cltodb(PCFS, CL)		/* clusters to disk blks */ \
    540 	((daddr_t)((CL) * (PCFS)->pcfs_spcl))
    541 
    542 #define	pc_dbdaddr(PCFS, DB)	/* sector to DEV_BSIZE "sector" addr */ \
    543 	((DB) << (PCFS)->pcfs_sdshift)
    544 
    545 #define	pc_daddrdb(PCFS, DADDR)	/* DEV_BSIZE "sector" addr to sector addr */ \
    546 	((DADDR) >> (PCFS)->pcfs_sdshift)
    547 
    548 #define	pc_cldaddr(PCFS, CL)	/* DEV_BSIZE "sector" addr for cluster */ \
    549 	pc_dbdaddr(PCFS, ((daddr_t)((PCFS)->pcfs_datastart +	\
    550 	pc_cltodb(PCFS, (CL) - PCF_FIRSTCLUSTER))))
    551 
    552 #define	pc_daddrcl(PCFS, DADDR)		/* cluster for disk address */	\
    553 	((int)(PCF_FIRSTCLUSTER +					\
    554 	pc_dbtocl(pc_daddrdb(PCFS, DADDR) - (PCFS)->pcfs_datastart)))
    555 
    556 /*
    557  * Number of directory entries per sector / cluster
    558  */
    559 #define	pc_direntpersec(PCFS)						\
    560 	((int)((PCFS)->pcfs_secsize / sizeof (struct pcdir)))
    561 
    562 #define	pc_direntpercl(PCFS)						\
    563 	((int)((PCFS)->pcfs_clsize  / sizeof (struct pcdir)))
    564 
    565 /*
    566  * out-of-range check for cluster numbers.
    567  */
    568 #define	pc_validcl(PCFS, CL)		/* check that cluster no is legit */ \
    569 	((int)(CL) >= PCF_FIRSTCLUSTER && \
    570 	    (int)(CL) < (PCFS)->pcfs_ncluster + PCF_FIRSTCLUSTER)
    571 
    572 /*
    573  * external routines.
    574  */
    575 extern int pc_lockfs(struct pcfs *, int, int); /* lock fs and get fat */
    576 extern void pc_unlockfs(struct pcfs *);	/* ulock the fs */
    577 extern int pc_getfat(struct pcfs *);	/* get fat from disk */
    578 extern void pc_invalfat(struct pcfs *);	/* invalidate incore fat */
    579 extern int pc_syncfat(struct pcfs *);	/* sync fat to disk */
    580 extern int pc_freeclusters(struct pcfs *);	/* num free clusters in fs */
    581 extern pc_cluster32_t pc_alloccluster(struct pcfs *, int);
    582 extern void pc_setcluster(struct pcfs *, pc_cluster32_t, pc_cluster32_t);
    583 extern void pc_mark_fat_updated(struct pcfs *fsp, pc_cluster32_t cn);
    584 extern int pc_fat_is_changed(struct pcfs *fsp, pc_cluster32_t bn);
    585 
    586 /*
    587  * debugging
    588  */
    589 extern int pcfsdebuglevel;
    590 #define	PC_DPRINTF0(level, A) \
    591 	if (pcfsdebuglevel >= level) \
    592 	    cmn_err(CE_CONT, (A))
    593 #define	PC_DPRINTF1(level, A, B) \
    594 	if (pcfsdebuglevel >= level) \
    595 	    cmn_err(CE_CONT, (A), (B))
    596 #define	PC_DPRINTF2(level, A, B, C) \
    597 	if (pcfsdebuglevel >= level) \
    598 	    cmn_err(CE_CONT, (A), (B), (C))
    599 #define	PC_DPRINTF3(level, A, B, C, D) \
    600 	if (pcfsdebuglevel >= level) \
    601 	    cmn_err(CE_CONT, (A), (B), (C), (D))
    602 #define	PC_DPRINTF4(level, A, B, C, D, E) \
    603 	if (pcfsdebuglevel >= level) \
    604 	    cmn_err(CE_CONT, (A), (B), (C), (D), (E))
    605 
    606 #ifdef	__cplusplus
    607 }
    608 #endif
    609 
    610 #endif	/* _SYS_FS_PC_FS_H */
    611