pc_fs.h revision 32d464954b2be825b7a73952618e7b6e73743730
/*
* 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
* 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/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
* by the PCFS kernel driver anymore.
*/
struct bootsec {
};
/*
* FAT32 volumes have a bigger boot sector. They include the normal
* boot sector.
*/
struct fat32_bootsec {
};
#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
/*
* Generic FAT BPB fields
*/
/*
* FAT12/16 extended BPB fields
*/
/*
* FAT32 extended BPB fields
*/
/*
* Validators
*/
#define VALID_SECSIZE(s) \
(s == 512 || s == 1024 || s == 2048 || s == 4096)
#define VALID_NUMFATS(n) ((n) > 0 && (n) < 8)
#define VALID_RSVDSEC(s) ((s) > 0)
/*
* 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)[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) ( \
#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 ...
*/
/*
* Validation results
*/
#define FAT12_VALIDMSK \
BPB_TOTSEC_OK | BPB_TOTSEC16_OK | \
#define FAT16_VALIDMSK \
/*
* 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 \
/*
* 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.
* to write them out to disk then.
*/
typedef struct fat_fsinfo {
} fat_fsi_t;
/*
* On-disk FSI. All values in little endian. Only FAT32 has this.
*/
typedef struct fat_od_fsi {
char fsi_reserved1[480];
char fsi_reserved2[12];
} fat_od_fsi_t;
struct pcfs {
int pcfs_flags; /* flags */
int pcfs_ldrive; /* logical DOS drive number */
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 */
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 */
int pcfs_fat_changemapsize; /* size of FAT changemap */
int pcfs_count; /* # of pcfs locks for pcfs_owner */
int pcfs_fatjustread; /* Used to flag a freshly found FAT */
int pcfs_secondswest; /* recording timezone for this fs */
int pcfs_rootblksize;
int pcfs_mediadesc; /* media descriptor */
};
/*
* flags
*/
/* 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
/*
* special cluster numbers in FAT
*/
/*
* file system constants
*/
/*
* file system parameter macros
*/
#define pc_clear_fatchanges(PCFS) \
((OFF) >= \
((PCFS)->pcfs_rdirsec & \
((PCFS)->pcfs_rdirsec & \
(PCFS)->pcfs_clsize): \
(PCFS)->pcfs_clsize)
((int)(PCF_FIRSTCLUSTER + \
/*
* Number of directory entries per sector / cluster
*/
#define pc_direntpersec(PCFS) \
#define pc_direntpercl(PCFS) \
/*
* out-of-range check for cluster numbers.
*/
((int)(CL) >= PCF_FIRSTCLUSTER && \
/*
* external routines.
*/
/*
* debugging
*/
extern int pcfsdebuglevel;
#define PC_DPRINTF0(level, A) \
if (pcfsdebuglevel >= level) \
#define PC_DPRINTF1(level, A, B) \
if (pcfsdebuglevel >= level) \
#define PC_DPRINTF2(level, A, B, C) \
if (pcfsdebuglevel >= level) \
#define PC_DPRINTF3(level, A, B, C, D) \
if (pcfsdebuglevel >= level) \
#define PC_DPRINTF4(level, A, B, C, D, E) \
if (pcfsdebuglevel >= level) \
#ifdef __cplusplus
}
#endif
#endif /* _SYS_FS_PC_FS_H */