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