xref: /onnv-gate/usr/src/cmd/fs.d/pcfs/fstyp/fstyp.c (revision 6563:c1f727d448c9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52212Sartem  * Common Development and Distribution License (the "License").
62212Sartem  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*6563Sdmick  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
270Sstevel@tonic-gate /*	  All Rights Reserved  	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
310Sstevel@tonic-gate  * under license from the Regents of the University of California.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
350Sstevel@tonic-gate 
360Sstevel@tonic-gate /*
372212Sartem  * libfstyp module for pcfs
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate #include <sys/param.h>
400Sstevel@tonic-gate #include <sys/types.h>
410Sstevel@tonic-gate #include <sys/mntent.h>
420Sstevel@tonic-gate #include <errno.h>
430Sstevel@tonic-gate #include <sys/fs/pc_fs.h>
440Sstevel@tonic-gate #include <sys/fs/pc_label.h>
452212Sartem #include <sys/fs/pc_dir.h>
460Sstevel@tonic-gate #include <sys/stat.h>
470Sstevel@tonic-gate #include <sys/vfs.h>
482212Sartem #include <stdio.h>
492212Sartem #include <unistd.h>
502212Sartem #include <string.h>
512212Sartem #include <strings.h>
522212Sartem #include <sys/mnttab.h>
532212Sartem #include <locale.h>
542212Sartem #include <libfstyp_module.h>
550Sstevel@tonic-gate 
562212Sartem #define	PC_LABEL_SIZE 11
572212Sartem 
58*6563Sdmick /* for the <sys/fs/pc_dir.h> PCDL_IS_LFN macro */
59*6563Sdmick int	enable_long_filenames = 1;
60*6563Sdmick 
612212Sartem struct fstyp_fat16_bs {
622212Sartem 	uint8_t		f_drvnum;
632212Sartem 	uint8_t		f_reserved1;
642212Sartem 	uint8_t		f_bootsig;
652212Sartem 	uint8_t		f_volid[4];
662212Sartem 	uint8_t		f_label[11];
672212Sartem 	uint8_t		f_typestring[8];
682212Sartem };
690Sstevel@tonic-gate 
702212Sartem struct fstyp_fat32_bs {
712212Sartem 	uint32_t	f_fatlength;
722212Sartem 	uint16_t	f_flags;
732212Sartem 	uint8_t		f_major;
742212Sartem 	uint8_t		f_minor;
752212Sartem 	uint32_t	f_rootcluster;
762212Sartem 	uint16_t	f_infosector;
772212Sartem 	uint16_t	f_backupboot;
782212Sartem 	uint8_t		f_reserved2[12];
792212Sartem 	uint8_t		f_drvnum;
802212Sartem 	uint8_t		f_reserved1;
812212Sartem 	uint8_t		f_bootsig;
822212Sartem 	uint8_t		f_volid[4];
832212Sartem 	uint8_t		f_label[11];
842212Sartem 	uint8_t		f_typestring[8];
852212Sartem };
860Sstevel@tonic-gate 
872212Sartem typedef struct fstyp_pcfs {
882212Sartem 	int		fd;
892212Sartem 	off_t		offset;
902212Sartem 	nvlist_t	*attr;
912212Sartem 	struct bootsec	bs;
922212Sartem 	struct fstyp_fat16_bs bs16;
932212Sartem 	struct fstyp_fat32_bs bs32;
942212Sartem 	ushort_t	bps;
952212Sartem 	int		fattype;
962212Sartem 	char		volume_label[PC_LABEL_SIZE + 1];
972212Sartem 
982212Sartem 	/* parameters derived or calculated per FAT spec */
992212Sartem 	ulong_t		FATSz;
1002212Sartem 	ulong_t		TotSec;
1012212Sartem 	ulong_t		RootDirSectors;
1022212Sartem 	ulong_t		FirstDataSector;
1032212Sartem 	ulong_t		DataSec;
1042212Sartem 	ulong_t		CountOfClusters;
1052212Sartem } fstyp_pcfs_t;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 
1082212Sartem /* We should eventually make the structs "packed" so these won't be needed */
1092212Sartem #define	PC_BPSEC(h)	ltohs((h)->bs.bps[0])
1102212Sartem #define	PC_RESSEC(h)	ltohs((h)->bs.res_sec[0])
1112212Sartem #define	PC_NROOTENT(h)	ltohs((h)->bs.rdirents[0])
1122212Sartem #define	PC_NSEC(h)	ltohs((h)->bs.numsect[0])
1132212Sartem #define	PC_DRVNUM(h)	(FSTYP_IS_32(h) ? (h)->bs32.f_drvnum : \
1142212Sartem 			    (h)->bs16.f_drvnum)
1152212Sartem #define	PC_VOLID(a)	(FSTYP_IS_32(h) ? ltohi((h)->bs32.f_volid[0]) : \
1162212Sartem 			    ltohi((h)->bs16.f_volid[0]))
1172212Sartem #define	PC_LABEL_ADDR(a) (FSTYP_IS_32(h) ? \
1182212Sartem 			    &((h)->bs32.f_label[0]) : &((h)->bs16.f_label[0]))
1192212Sartem 
1202212Sartem #define	FSTYP_IS_32(h)	((h)->fattype == 32)
1212212Sartem 
1222212Sartem #define	FSTYP_MAX_CLUSTER_SIZE	(64 * 1024)	/* though officially 32K */
1232212Sartem #define	FSTYP_MAX_DIR_SIZE	(65536 * 32)
1242212Sartem 
1252212Sartem static int	read_bootsec(fstyp_pcfs_t *h);
1262212Sartem static int	valid_media(fstyp_pcfs_t *h);
1272212Sartem static int	well_formed(fstyp_pcfs_t *h);
1282212Sartem static void	calculate_parameters(fstyp_pcfs_t *h);
1292212Sartem static void	determine_fattype(fstyp_pcfs_t *h);
1302212Sartem static void	get_label(fstyp_pcfs_t *h);
1312212Sartem static void	get_label_16(fstyp_pcfs_t *h);
1322212Sartem static void	get_label_32(fstyp_pcfs_t *h);
1332212Sartem static int	next_cluster_32(fstyp_pcfs_t *h, int n);
1342212Sartem static boolean_t dir_find_label(fstyp_pcfs_t *h, struct pcdir *d, int nent);
1352212Sartem static int	is_pcfs(fstyp_pcfs_t *h);
1362212Sartem static int	dumpfs(fstyp_pcfs_t *h, FILE *fout, FILE *ferr);
1372212Sartem static int	get_attr(fstyp_pcfs_t *h);
1382212Sartem 
1392212Sartem int	fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle);
1402212Sartem void	fstyp_mod_fini(fstyp_mod_handle_t handle);
1412212Sartem int	fstyp_mod_ident(fstyp_mod_handle_t handle);
1422212Sartem int	fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp);
1432212Sartem int	fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr);
1442212Sartem 
1452212Sartem int
fstyp_mod_init(int fd,off_t offset,fstyp_mod_handle_t * handle)1462212Sartem fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle)
1472212Sartem {
1482212Sartem 	struct fstyp_pcfs *h;
1492212Sartem 
1502212Sartem 	if ((h = calloc(1, sizeof (struct fstyp_pcfs))) == NULL) {
1512212Sartem 		return (FSTYP_ERR_NOMEM);
1522212Sartem 	}
1532212Sartem 	h->fd = fd;
1542212Sartem 	h->offset = offset;
1550Sstevel@tonic-gate 
1562212Sartem 	*handle = (fstyp_mod_handle_t)h;
1572212Sartem 	return (0);
1582212Sartem }
1592212Sartem 
1602212Sartem void
fstyp_mod_fini(fstyp_mod_handle_t handle)1612212Sartem fstyp_mod_fini(fstyp_mod_handle_t handle)
1622212Sartem {
1632212Sartem 	struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle;
1642212Sartem 
1652212Sartem 	if (h->attr == NULL) {
1662212Sartem 		nvlist_free(h->attr);
1672212Sartem 		h->attr = NULL;
1682212Sartem 	}
1692212Sartem 	free(h);
1702212Sartem }
1712212Sartem 
1722212Sartem int
fstyp_mod_ident(fstyp_mod_handle_t handle)1732212Sartem fstyp_mod_ident(fstyp_mod_handle_t handle)
1742212Sartem {
1752212Sartem 	struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle;
1762212Sartem 
1772212Sartem 	return (is_pcfs(h));
1782212Sartem }
1792212Sartem 
1802212Sartem int
fstyp_mod_get_attr(fstyp_mod_handle_t handle,nvlist_t ** attrp)1812212Sartem fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp)
1822212Sartem {
1832212Sartem 	struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle;
1842212Sartem 	int error;
1852212Sartem 
1862212Sartem 	if (h->attr == NULL) {
1872212Sartem 		if (nvlist_alloc(&h->attr, NV_UNIQUE_NAME_TYPE, 0)) {
1882212Sartem 			return (FSTYP_ERR_NOMEM);
1892212Sartem 		}
1902212Sartem 		if ((error = get_attr(h)) != 0) {
1912212Sartem 			nvlist_free(h->attr);
1922212Sartem 			h->attr = NULL;
1932212Sartem 			return (error);
1942212Sartem 		}
1952212Sartem 	}
1962212Sartem 
1972212Sartem 	*attrp = h->attr;
1982212Sartem 	return (0);
1992212Sartem }
2002212Sartem 
2012212Sartem int
fstyp_mod_dump(fstyp_mod_handle_t handle,FILE * fout,FILE * ferr)2022212Sartem fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr)
2032212Sartem {
2042212Sartem 	struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle;
2052212Sartem 
2062212Sartem 	return (dumpfs(h, fout, ferr));
2072212Sartem }
2082212Sartem 
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate /*
2112212Sartem  * Read in boot sector. Convert into host endianness where possible.
2120Sstevel@tonic-gate  */
2132212Sartem static int
read_bootsec(fstyp_pcfs_t * h)2142212Sartem read_bootsec(fstyp_pcfs_t *h)
2152212Sartem {
2162212Sartem 	char 	buf[PC_SECSIZE];
2170Sstevel@tonic-gate 
2182212Sartem 	(void) lseek(h->fd, h->offset, SEEK_SET);
2192212Sartem 	if (read(h->fd, buf, sizeof (buf)) != sizeof (buf)) {
2202212Sartem 		return (FSTYP_ERR_IO);
2212212Sartem 	}
2220Sstevel@tonic-gate 
2232212Sartem 	bcopy(buf, &h->bs, sizeof (h->bs));
2242212Sartem 	bcopy(buf + sizeof (struct bootsec), &h->bs16, sizeof (h->bs16));
2252212Sartem 	bcopy(buf + sizeof (struct bootsec), &h->bs32, sizeof (h->bs32));
2260Sstevel@tonic-gate 
2272212Sartem 	h->bs.fatsec = ltohs(h->bs.fatsec);
2282212Sartem 	h->bs.spt = ltohs(h->bs.spt);
2292212Sartem 	h->bs.nhead = ltohs(h->bs.nhead);
2302212Sartem 	h->bs.hiddensec = ltohi(h->bs.hiddensec);
2312212Sartem 	h->bs.totalsec = ltohi(h->bs.totalsec);
2320Sstevel@tonic-gate 
2332212Sartem 	h->bs32.f_fatlength = ltohi(h->bs32.f_fatlength);
2342212Sartem 	h->bs32.f_flags = ltohs(h->bs32.f_flags);
2352212Sartem 	h->bs32.f_rootcluster = ltohi(h->bs32.f_rootcluster);
2362212Sartem 	h->bs32.f_infosector = ltohs(h->bs32.f_infosector);
2372212Sartem 	h->bs32.f_backupboot = ltohs(h->bs32.f_backupboot);
2382212Sartem 
2392212Sartem 	h->bps = PC_BPSEC(h);
2400Sstevel@tonic-gate 
241452Sjkennedy 	return (0);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate 
2442212Sartem static int
valid_media(fstyp_pcfs_t * h)2452212Sartem valid_media(fstyp_pcfs_t *h)
2460Sstevel@tonic-gate {
2472212Sartem 	switch (h->bs.mediadesriptor) {
2480Sstevel@tonic-gate 	case MD_FIXED:
2490Sstevel@tonic-gate 	case SS8SPT:
2500Sstevel@tonic-gate 	case DS8SPT:
2510Sstevel@tonic-gate 	case SS9SPT:
2520Sstevel@tonic-gate 	case DS9SPT:
2530Sstevel@tonic-gate 	case DS18SPT:
2540Sstevel@tonic-gate 	case DS9_15SPT:
2550Sstevel@tonic-gate 		return (1);
2560Sstevel@tonic-gate 	default:
2570Sstevel@tonic-gate 		return (0);
2580Sstevel@tonic-gate 	}
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2612212Sartem static int
well_formed(fstyp_pcfs_t * h)2622212Sartem well_formed(fstyp_pcfs_t *h)
2630Sstevel@tonic-gate {
2640Sstevel@tonic-gate 	int fatmatch;
2650Sstevel@tonic-gate 
2662212Sartem 	if (h->bs16.f_bootsig == 0x29) {
2672212Sartem 		fatmatch = ((h->bs16.f_typestring[0] == 'F' &&
268*6563Sdmick 		    h->bs16.f_typestring[1] == 'A' &&
269*6563Sdmick 		    h->bs16.f_typestring[2] == 'T') &&
270*6563Sdmick 		    (h->bs.fatsec > 0) &&
271*6563Sdmick 		    ((PC_NSEC(h) == 0 && h->bs.totalsec > 0) ||
272*6563Sdmick 		    PC_NSEC(h) > 0));
2732212Sartem 	} else if (h->bs32.f_bootsig == 0x29) {
2742212Sartem 		fatmatch = ((h->bs32.f_typestring[0] == 'F' &&
275*6563Sdmick 		    h->bs32.f_typestring[1] == 'A' &&
276*6563Sdmick 		    h->bs32.f_typestring[2] == 'T') &&
277*6563Sdmick 		    (h->bs.fatsec == 0 && h->bs32.f_fatlength > 0) &&
278*6563Sdmick 		    ((PC_NSEC(h) == 0 && h->bs.totalsec > 0) ||
279*6563Sdmick 		    PC_NSEC(h) > 0));
2802212Sartem 	} else {
2812212Sartem 		fatmatch = (PC_NSEC(h) > 0 && h->bs.fatsec > 0);
2822212Sartem 	}
2832212Sartem 
2842212Sartem 	return (fatmatch && h->bps > 0 && h->bps % 512 == 0 &&
285*6563Sdmick 	    h->bs.spcl > 0 && PC_RESSEC(h) >= 1 && h->bs.nfat > 0);
2862212Sartem }
2872212Sartem 
2882212Sartem static void
calculate_parameters(fstyp_pcfs_t * h)2892212Sartem calculate_parameters(fstyp_pcfs_t *h)
2902212Sartem {
2912212Sartem 	if (PC_NSEC(h) != 0) {
2922212Sartem 		h->TotSec = PC_NSEC(h);
2932212Sartem 	} else {
2942212Sartem 		h->TotSec = h->bs.totalsec;
2952212Sartem 	}
2962212Sartem 	if (h->bs.fatsec != 0) {
2972212Sartem 		h->FATSz = h->bs.fatsec;
2982212Sartem 	} else {
2992212Sartem 		h->FATSz = h->bs32.f_fatlength;
3002212Sartem 	}
3012212Sartem 	if ((h->bps == 0) || (h->bs.spcl == 0)) {
3022212Sartem 		return;
3032212Sartem 	}
3042212Sartem 	h->RootDirSectors =
3052212Sartem 	    ((PC_NROOTENT(h) * 32) + (h->bps - 1)) / h->bps;
3062212Sartem 	h->FirstDataSector =
3072212Sartem 	    PC_RESSEC(h) + h->bs.nfat * h->FATSz + h->RootDirSectors;
3082212Sartem 	h->DataSec = h->TotSec - h->FirstDataSector;
3092212Sartem 	h->CountOfClusters = h->DataSec / h->bs.spcl;
3102212Sartem }
3112212Sartem 
3122212Sartem static void
determine_fattype(fstyp_pcfs_t * h)3132212Sartem determine_fattype(fstyp_pcfs_t *h)
3142212Sartem {
3152212Sartem 	if ((h->CountOfClusters >= 4085 && h->CountOfClusters <= 4095) ||
3162212Sartem 	    (h->CountOfClusters >= 65525 && h->CountOfClusters <= 65535)) {
3172212Sartem 		h->fattype = 0;
3182212Sartem 	} else if (h->CountOfClusters < 4085) {
3192212Sartem 		h->fattype = 12;
3202212Sartem 	} else if (h->CountOfClusters < 65525) {
3212212Sartem 		h->fattype = 16;
3222212Sartem 	} else {
3232212Sartem 		h->fattype = 32;
3242212Sartem 	}
3252212Sartem }
3262212Sartem 
3272212Sartem static void
get_label(fstyp_pcfs_t * h)3282212Sartem get_label(fstyp_pcfs_t *h)
3292212Sartem {
3302212Sartem 	/*
3312212Sartem 	 * Use label from the boot sector by default.
3322212Sartem 	 * Can overwrite later with the one from root directory.
3332212Sartem 	 */
3342212Sartem 	(void) memcpy(h->volume_label, PC_LABEL_ADDR(h), PC_LABEL_SIZE);
3352212Sartem 	h->volume_label[PC_LABEL_SIZE] = '\0';
3362212Sartem 
3372212Sartem 	if (h->fattype == 0) {
3382212Sartem 		return;
3392212Sartem 	} else if (FSTYP_IS_32(h)) {
3402212Sartem 		get_label_32(h);
3410Sstevel@tonic-gate 	} else {
3422212Sartem 		get_label_16(h);
3432212Sartem 	}
3442212Sartem }
3452212Sartem 
3462212Sartem /*
3472212Sartem  * Get volume label from the root directory entry.
3482212Sartem  * In FAT12/16 the root directory is of fixed size.
3492212Sartem  * It immediately follows the FATs
3502212Sartem  */
3512212Sartem static void
get_label_16(fstyp_pcfs_t * h)3522212Sartem get_label_16(fstyp_pcfs_t *h)
3532212Sartem {
3542212Sartem 	ulong_t	FirstRootDirSecNum;
3552212Sartem 	int	secsize;
3562212Sartem 	off_t	offset;
3572212Sartem 	uint8_t	buf[PC_SECSIZE * 4];
3582212Sartem 	int	i;
3592212Sartem 	int	nent, resid;
3602212Sartem 
3612212Sartem 	if ((secsize = h->bps) > sizeof (buf)) {
3622212Sartem 		return;
3632212Sartem 	}
3642212Sartem 
3652212Sartem 	FirstRootDirSecNum = PC_RESSEC(h) + h->bs.nfat * h->bs.fatsec;
3662212Sartem 	offset = h->offset + FirstRootDirSecNum * secsize;
3672212Sartem 	resid = PC_NROOTENT(h);
3682212Sartem 
3692212Sartem 	for (i = 0; i < h->RootDirSectors; i++) {
3702212Sartem 		(void) lseek(h->fd, offset, SEEK_SET);
3712212Sartem 		if (read(h->fd, buf, secsize) != secsize) {
3722212Sartem 			return;
3732212Sartem 		}
3742212Sartem 
3752212Sartem 		nent = secsize / sizeof (struct pcdir);
3762212Sartem 		if (nent > resid) {
3772212Sartem 			nent = resid;
3782212Sartem 		}
3792212Sartem 		if (dir_find_label(h, (struct pcdir *)buf, nent)) {
3802212Sartem 			return;
3812212Sartem 		}
3822212Sartem 
3832212Sartem 		resid -= nent;
3842212Sartem 		offset += PC_SECSIZE;
3852212Sartem 	}
3862212Sartem }
3872212Sartem 
3882212Sartem /*
3892212Sartem  * Get volume label from the root directory entry.
3902212Sartem  * In FAT32 root is a usual directory, a cluster chain.
3912212Sartem  * It starts at BPB_RootClus.
3922212Sartem  */
3932212Sartem static void
get_label_32(fstyp_pcfs_t * h)3942212Sartem get_label_32(fstyp_pcfs_t *h)
3952212Sartem {
3962212Sartem 	off_t	offset;
3972212Sartem 	int	clustersize;
3982212Sartem 	int	n;
3992212Sartem 	ulong_t	FirstSectorofCluster;
4002212Sartem 	uint8_t	*buf;
4012212Sartem 	int	nent;
4022212Sartem 	int	cnt = 0;
4032212Sartem 
4042212Sartem 	clustersize = h->bs.spcl * h->bps;
4052212Sartem 	if ((clustersize == 0) || (clustersize > FSTYP_MAX_CLUSTER_SIZE) ||
4062212Sartem 	    ((buf = calloc(1, clustersize)) == NULL)) {
4072212Sartem 		return;
4082212Sartem 	}
4092212Sartem 
4102212Sartem 	for (n = h->bs32.f_rootcluster; n != 0; n = next_cluster_32(h, n)) {
4112212Sartem 		FirstSectorofCluster =
4122212Sartem 		    (n - 2) * h->bs.spcl + h->FirstDataSector;
4132212Sartem 		offset = h->offset + FirstSectorofCluster * h->bps;
4142212Sartem 		(void) lseek(h->fd, offset, SEEK_SET);
4152212Sartem 		if (read(h->fd, buf, clustersize) != clustersize) {
4162212Sartem 			break;
4172212Sartem 		}
4182212Sartem 
4192212Sartem 		nent = clustersize / sizeof (struct pcdir);
4202212Sartem 		if (dir_find_label(h, (struct pcdir *)buf, nent)) {
4212212Sartem 			break;
4222212Sartem 		}
4232212Sartem 
4242212Sartem 		if (++cnt > FSTYP_MAX_DIR_SIZE / clustersize) {
4252212Sartem 			break;
4262212Sartem 		}
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate 
4292212Sartem 	free(buf);
4302212Sartem }
4312212Sartem 
4322212Sartem /*
4332212Sartem  * Get a FAT entry pointing to the next file cluster
4342212Sartem  */
4352212Sartem int
next_cluster_32(fstyp_pcfs_t * h,int n)4362212Sartem next_cluster_32(fstyp_pcfs_t *h, int n)
4372212Sartem {
4382212Sartem 	uint8_t	buf[PC_SECSIZE];
4392212Sartem 	ulong_t	ThisFATSecNum;
4402212Sartem 	ulong_t	ThisFATEntOffset;
4412212Sartem 	off_t	offset;
4422212Sartem 	uint32_t val;
4432212Sartem 	int	next = 0;
4442212Sartem 
4452212Sartem 	ThisFATSecNum = PC_RESSEC(h) + (n * 4) / h->bps;
4462212Sartem 	ThisFATEntOffset = (n * 4) % h->bps;
4472212Sartem 	offset = h->offset + ThisFATSecNum * h->bps;
4482212Sartem 
4492212Sartem 	(void) lseek(h->fd, offset, SEEK_SET);
4502212Sartem 	if (read(h->fd, buf, sizeof (buf)) == sizeof (buf)) {
4512212Sartem 		val = buf[ThisFATEntOffset] & 0x0fffffff;
4522212Sartem 		next = ltohi(val);
4532212Sartem 	}
4542212Sartem 
4552212Sartem 	return (next);
4562212Sartem }
4572212Sartem 
4582212Sartem /*
4592212Sartem  * Given an array of pcdir structs, find one containing volume label.
4602212Sartem  */
4612212Sartem static boolean_t
dir_find_label(fstyp_pcfs_t * h,struct pcdir * d,int nent)4622212Sartem dir_find_label(fstyp_pcfs_t *h, struct pcdir *d, int nent)
4632212Sartem {
4642212Sartem 	int	i;
4652212Sartem 
4662212Sartem 	for (i = 0; i < nent; i++, d++) {
467*6563Sdmick 		if (PCDL_IS_LFN(d))
468*6563Sdmick 			continue;
4692212Sartem 		if ((d->pcd_filename[0] != PCD_UNUSED) &&
4702212Sartem 		    (d->pcd_filename[0] != PCD_ERASED) &&
4712212Sartem 		    ((d->pcd_attr & (PCA_LABEL | PCA_DIR)) == PCA_LABEL) &&
4722212Sartem 		    (d->un.pcd_scluster_hi == 0) &&
4732212Sartem 		    (d->pcd_scluster_lo == 0)) {
4742212Sartem 			(void) memcpy(h->volume_label, d->pcd_filename,
4752212Sartem 			    PC_LABEL_SIZE);
4762212Sartem 			h->volume_label[PC_LABEL_SIZE] = '\0';
4772212Sartem 			return (B_TRUE);
4782212Sartem 		}
4792212Sartem 	}
4802212Sartem 	return (B_FALSE);
4812212Sartem }
4822212Sartem 
4832212Sartem static int
is_pcfs(fstyp_pcfs_t * h)4842212Sartem is_pcfs(fstyp_pcfs_t *h)
4852212Sartem {
4862212Sartem 	int	error;
4872212Sartem 
4882212Sartem 	if ((error = read_bootsec(h)) != 0) {
4892212Sartem 		return (error);
4902212Sartem 	}
4912212Sartem 	if (!valid_media(h)) {
4922212Sartem 		return (FSTYP_ERR_NO_MATCH);
4932212Sartem 	}
4942212Sartem 	if (!well_formed(h)) {
4952212Sartem 		return (FSTYP_ERR_NO_MATCH);
4962212Sartem 	}
4972212Sartem 
4982212Sartem 	calculate_parameters(h);
4992212Sartem 	determine_fattype(h);
5002212Sartem 	get_label(h);
5012212Sartem 
5022212Sartem 	return (0);
5030Sstevel@tonic-gate }
5042212Sartem 
5052212Sartem /* ARGSUSED */
5062212Sartem static int
dumpfs(fstyp_pcfs_t * h,FILE * fout,FILE * ferr)5072212Sartem dumpfs(fstyp_pcfs_t *h, FILE *fout, FILE *ferr)
5082212Sartem {
5092212Sartem 	(void) fprintf(fout,
5102212Sartem 	    "Bytes Per Sector  %d\t\tSectors Per Cluster    %d\n",
5112212Sartem 	    h->bps, h->bs.spcl);
5122212Sartem 	(void) fprintf(fout,
5132212Sartem 	    "Reserved Sectors  %d\t\tNumber of FATs         %d\n",
5142212Sartem 	    (unsigned short)PC_RESSEC(h), h->bs.nfat);
5152212Sartem 	(void) fprintf(fout,
5162212Sartem 	    "Root Dir Entries  %d\t\tNumber of Sectors      %d\n",
5172212Sartem 	    (unsigned short)PC_NROOTENT(h), (unsigned short)PC_NSEC(h));
5182212Sartem 	(void) fprintf(fout,
5192212Sartem 	    "Sectors Per FAT   %d\t\tSectors Per Track      %d\n",
5202212Sartem 	    h->bs.fatsec, h->bs.spt);
5212212Sartem 	(void) fprintf(fout,
5222212Sartem 	    "Number of Heads   %d\t\tNumber Hidden Sectors  %d\n",
5232212Sartem 	    h->bs.nhead, h->bs.hiddensec);
5242212Sartem 	(void) fprintf(fout, "Volume ID: 0x%x\n", PC_VOLID(h));
5252212Sartem 	(void) fprintf(fout, "Volume Label: %s\n", h->volume_label);
5262212Sartem 	(void) fprintf(fout, "Drive Number: 0x%x\n", PC_DRVNUM(h));
5272212Sartem 	(void) fprintf(fout, "Media Type: 0x%x   ", h->bs.mediadesriptor);
5282212Sartem 
5292212Sartem 	switch (h->bs.mediadesriptor) {
5302212Sartem 	case MD_FIXED:
5312212Sartem 		(void) fprintf(fout, "\"Fixed\" Disk\n");
5322212Sartem 		break;
5332212Sartem 	case SS8SPT:
5342212Sartem 		(void) fprintf(fout, "Single Sided, 8 Sectors Per Track\n");
5352212Sartem 		break;
5362212Sartem 	case DS8SPT:
5372212Sartem 		(void) fprintf(fout, "Double Sided, 8 Sectors Per Track\n");
5382212Sartem 		break;
5392212Sartem 	case SS9SPT:
5402212Sartem 		(void) fprintf(fout, "Single Sided, 9 Sectors Per Track\n");
5412212Sartem 		break;
5422212Sartem 	case DS9SPT:
5432212Sartem 		(void) fprintf(fout, "Double Sided, 9 Sectors Per Track\n");
5442212Sartem 		break;
5452212Sartem 	case DS18SPT:
5462212Sartem 		(void) fprintf(fout, "Double Sided, 18 Sectors Per Track\n");
5472212Sartem 		break;
5482212Sartem 	case DS9_15SPT:
5492212Sartem 		(void) fprintf(fout, "Double Sided, 9-15 Sectors Per Track\n");
5502212Sartem 		break;
5512212Sartem 	default:
5522212Sartem 		(void) fprintf(fout, "Unknown Media Type\n");
5532212Sartem 	}
5542212Sartem 
5552212Sartem 	return (0);
5562212Sartem }
5572212Sartem 
5582212Sartem #define	ADD_STRING(h, name, value) \
5592212Sartem 	if (nvlist_add_string(h->attr, name, value) != 0) { \
5602212Sartem 		return (FSTYP_ERR_NOMEM); \
5612212Sartem 	}
5622212Sartem 
5632212Sartem #define	ADD_UINT32(h, name, value) \
5642212Sartem 	if (nvlist_add_uint32(h->attr, name, value) != 0) { \
5652212Sartem 		return (FSTYP_ERR_NOMEM); \
5662212Sartem 	}
5672212Sartem 
5682212Sartem #define	ADD_UINT64(h, name, value) \
5692212Sartem 	if (nvlist_add_uint64(h->attr, name, value) != 0) { \
5702212Sartem 		return (FSTYP_ERR_NOMEM); \
5712212Sartem 	}
5722212Sartem 
5732212Sartem #define	ADD_BOOL(h, name, value) \
5742212Sartem 	if (nvlist_add_boolean_value(h->attr, name, value) != 0) { \
5752212Sartem 		return (FSTYP_ERR_NOMEM); \
5762212Sartem 	}
5772212Sartem 
5782212Sartem static int
get_attr(fstyp_pcfs_t * h)5792212Sartem get_attr(fstyp_pcfs_t *h)
5802212Sartem {
5812212Sartem 	char	s[64];
5822212Sartem 
5832212Sartem 	ADD_UINT32(h, "bytes_per_sector", h->bps);
5842212Sartem 	ADD_UINT32(h, "sectors_per_cluster", h->bs.spcl);
5852212Sartem 	ADD_UINT32(h, "reserved_sectors", PC_RESSEC(h));
5862212Sartem 	ADD_UINT32(h, "fats", h->bs.nfat);
5872212Sartem 	ADD_UINT32(h, "root_entry_count", PC_NROOTENT(h));
5882212Sartem 	ADD_UINT32(h, "total_sectors_16", PC_NSEC(h));
5892212Sartem 	ADD_UINT32(h, "media", h->bs.mediadesriptor);
5902212Sartem 	ADD_UINT32(h, "fat_size_16", h->bs.fatsec);
5912212Sartem 	ADD_UINT32(h, "sectors_per_track", h->bs.spt);
5922212Sartem 	ADD_UINT32(h, "heads", h->bs.nhead);
5932212Sartem 	ADD_UINT32(h, "hidden_sectors", h->bs.hiddensec);
5942212Sartem 	ADD_UINT32(h, "total_sectors_32", h->bs.totalsec);
5952212Sartem 	ADD_UINT32(h, "drive_number", PC_DRVNUM(h));
5962212Sartem 	ADD_UINT32(h, "volume_id", PC_VOLID(h));
5972212Sartem 	ADD_STRING(h, "volume_label", h->volume_label);
5982212Sartem 	if (FSTYP_IS_32(h)) {
5992212Sartem 		ADD_UINT32(h, "fat_size_32", h->bs32.f_fatlength);
6002212Sartem 	}
6012212Sartem 	ADD_UINT32(h, "total_sectors", h->TotSec);
6022212Sartem 	ADD_UINT32(h, "fat_size", h->FATSz);
6032212Sartem 	ADD_UINT32(h, "count_of_clusters", h->CountOfClusters);
6042212Sartem 	ADD_UINT32(h, "fat_entry_size", h->fattype);
6052212Sartem 
6062212Sartem 	ADD_BOOL(h, "gen_clean", B_TRUE);
6072212Sartem 	if (PC_VOLID(a) != 0) {
6082212Sartem 		(void) snprintf(s, sizeof (s), "%08x", PC_VOLID(a));
6092212Sartem 		ADD_STRING(h, "gen_guid", s);
6102212Sartem 	}
6112212Sartem 	(void) snprintf(s, sizeof (s), "%d", h->fattype);
6122212Sartem 	ADD_STRING(h, "gen_version", s);
6132212Sartem 	ADD_STRING(h, "gen_volume_label", h->volume_label);
6142212Sartem 
6152212Sartem 	return (0);
6162212Sartem }
617