1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the
| 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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License.
| 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License.
|
8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22/*
| 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/*
|
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
| 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
24 * Use is subject to license terms. 25 */ 26 27/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28/* All Rights Reserved */ 29 30/* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35#pragma ident "%Z%%M% %I% %E% SMI" 36 37/*
| 23 * Use is subject to license terms. 24 */ 25 26/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27/* All Rights Reserved */ 28 29/* 30 * Portions of this source code were derived from Berkeley 4.3 BSD 31 * under license from the Regents of the University of California. 32 */ 33 34#pragma ident "%Z%%M% %I% %E% SMI" 35 36/*
|
38 * fstyp 39 * 40 * Designed to work with block devices (e.g., /dev/diskette), not 41 * raw devices (e.g., /dev/rdiskette)
| 37 * libfstyp module for pcfs
|
42 */ 43#include <sys/param.h> 44#include <sys/types.h> 45#include <sys/mntent.h> 46#include <errno.h> 47#include <sys/fs/pc_fs.h> 48#include <sys/fs/pc_label.h>
| 38 */ 39#include <sys/param.h> 40#include <sys/types.h> 41#include <sys/mntent.h> 42#include <errno.h> 43#include <sys/fs/pc_fs.h> 44#include <sys/fs/pc_label.h>
|
| 45#include <sys/fs/pc_dir.h>
|
49#include <sys/stat.h> 50#include <sys/vfs.h>
| 46#include <sys/stat.h> 47#include <sys/vfs.h>
|
51
| |
52#include <stdio.h>
| 48#include <stdio.h>
|
| 49#include <unistd.h> 50#include <string.h> 51#include <strings.h>
|
53#include <sys/mnttab.h>
| 52#include <sys/mnttab.h>
|
54
| |
55#include <locale.h>
| 53#include <locale.h>
|
| 54#include <libfstyp_module.h>
|
56
| 55
|
57extern offset_t llseek();
| 56#define PC_LABEL_SIZE 11
|
58
| 57
|
| 58struct fstyp_fat16_bs { 59 uint8_t f_drvnum; 60 uint8_t f_reserved1; 61 uint8_t f_bootsig; 62 uint8_t f_volid[4]; 63 uint8_t f_label[11]; 64 uint8_t f_typestring[8]; 65};
|
59
| 66
|
60#define PC_BPSEC(a) ((a[12]<<8)+a[11]) /* bytes per sector */ 61#define PC_SPC(a) (a[13]) /* sectors per cluster */ 62#define PC_RESSEC(a) ((a[15]<<8)+a[14]) /* reserved sectors */ 63#define PC_NFAT(a) (a[16]) /* number of fats */ 64#define PC_NROOTENT(a) ((a[18]<<8)+a[17]) /* number of root dir entries */ 65#define PC_MEDIA(a) (a[21]) /* media descriptor */ 66#define PC_SPT(a) ((a[25]<<8)+a[24]) /* sectors per track */ 67#define PC_NHEAD(a) ((a[27]<<8)+a[26]) /* number of heads */ 68#define PC_HIDSEC(a) ((a[29]<<8)+a[28]) /* number of hidden sectors */ 69#define PC_DRVNUM(a) (a[36]) /* drive number */ 70#define PC_LAB_ADDR(a) (&a[43]) /* addr of volume label */ 71#define LABEL_SIZE 11 /* size of volume label */
| 67struct fstyp_fat32_bs { 68 uint32_t f_fatlength; 69 uint16_t f_flags; 70 uint8_t f_major; 71 uint8_t f_minor; 72 uint32_t f_rootcluster; 73 uint16_t f_infosector; 74 uint16_t f_backupboot; 75 uint8_t f_reserved2[12]; 76 uint8_t f_drvnum; 77 uint8_t f_reserved1; 78 uint8_t f_bootsig; 79 uint8_t f_volid[4]; 80 uint8_t f_label[11]; 81 uint8_t f_typestring[8]; 82};
|
72
| 83
|
73/* 74 * Parse out all the following forms as unsigned quantities. It would 75 * not be unusual for them to be large enough that the high bit would be 76 * set and they would then be misinterpreted as negative quantities. 77 * 78 * The values are: 79 * number of sectors 80 * big number of sectors (MSDOS4.0 and later) 81 * sectors/FAT 82 * big sectors/FAT (FAT32 only) 83 */ 84#define PC_NSEC(a) ((unsigned short)((a[20]<<8)+a[19])) 85#define PC_BIGNSEC(a) ((unsigned)((a[35]<<24)+(a[34]<<16)+(a[33]<<8)+a[32])) 86#define PC_SPF(a) ((unsigned short)((a[23]<<8)+a[22])) 87#define PC_BIGSPF(a) ((unsigned)((a[39]<<24)+(a[38]<<16)+(a[37]<<8)+a[36]))
| 84typedef struct fstyp_pcfs { 85 int fd; 86 off_t offset; 87 nvlist_t *attr; 88 struct bootsec bs; 89 struct fstyp_fat16_bs bs16; 90 struct fstyp_fat32_bs bs32; 91 ushort_t bps; 92 int fattype; 93 char volume_label[PC_LABEL_SIZE + 1];
|
88
| 94
|
89/* 90 * Boolean macros 91 */ 92#define PC_EXTSIG(a) (a[38] == 0x29) /* do we have an extended BPB? */ 93#define PC_EXTSIG32(a) (a[66] == 0x29) /* do we have FAT32 w/ extended BPB? */
| 95 /* parameters derived or calculated per FAT spec */ 96 ulong_t FATSz; 97 ulong_t TotSec; 98 ulong_t RootDirSectors; 99 ulong_t FirstDataSector; 100 ulong_t DataSec; 101 ulong_t CountOfClusters; 102} fstyp_pcfs_t;
|
94
| 103
|
95int vflag = 0; /* verbose output */ 96int errflag = 0; 97char *cbasename; 98char *special; 99char *fstype;
| |
100
| 104
|
101static void usage(void); 102static void dumpfs(char *name); 103static int valid_media(unsigned char media_type);
| 105/* We should eventually make the structs "packed" so these won't be needed */ 106#define PC_BPSEC(h) ltohs((h)->bs.bps[0]) 107#define PC_RESSEC(h) ltohs((h)->bs.res_sec[0]) 108#define PC_NROOTENT(h) ltohs((h)->bs.rdirents[0]) 109#define PC_NSEC(h) ltohs((h)->bs.numsect[0]) 110#define PC_DRVNUM(h) (FSTYP_IS_32(h) ? (h)->bs32.f_drvnum : \ 111 (h)->bs16.f_drvnum) 112#define PC_VOLID(a) (FSTYP_IS_32(h) ? ltohi((h)->bs32.f_volid[0]) : \ 113 ltohi((h)->bs16.f_volid[0])) 114#define PC_LABEL_ADDR(a) (FSTYP_IS_32(h) ? \ 115 &((h)->bs32.f_label[0]) : &((h)->bs16.f_label[0]))
|
104
| 116
|
| 117#define FSTYP_IS_32(h) ((h)->fattype == 32) 118 119#define FSTYP_MAX_CLUSTER_SIZE (64 * 1024) /* though officially 32K */ 120#define FSTYP_MAX_DIR_SIZE (65536 * 32) 121 122static int read_bootsec(fstyp_pcfs_t *h); 123static int valid_media(fstyp_pcfs_t *h); 124static int well_formed(fstyp_pcfs_t *h); 125static void calculate_parameters(fstyp_pcfs_t *h); 126static void determine_fattype(fstyp_pcfs_t *h); 127static void get_label(fstyp_pcfs_t *h); 128static void get_label_16(fstyp_pcfs_t *h); 129static void get_label_32(fstyp_pcfs_t *h); 130static int next_cluster_32(fstyp_pcfs_t *h, int n); 131static boolean_t dir_find_label(fstyp_pcfs_t *h, struct pcdir *d, int nent); 132static int is_pcfs(fstyp_pcfs_t *h); 133static int dumpfs(fstyp_pcfs_t *h, FILE *fout, FILE *ferr); 134static int get_attr(fstyp_pcfs_t *h); 135 136int fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle); 137void fstyp_mod_fini(fstyp_mod_handle_t handle); 138int fstyp_mod_ident(fstyp_mod_handle_t handle); 139int fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp); 140int fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr); 141
|
105int
| 142int
|
106main(int argc, char *argv[])
| 143fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle)
|
107{
| 144{
|
108 int c;
| 145 struct fstyp_pcfs *h;
|
109
| 146
|
110 (void) setlocale(LC_ALL, ""); 111#if !defined(TEXT_DOMAIN) 112#define TEXT_DOMAIN "SYS_TEST" 113#endif 114 (void) textdomain(TEXT_DOMAIN);
| 147 if ((h = calloc(1, sizeof (struct fstyp_pcfs))) == NULL) { 148 return (FSTYP_ERR_NOMEM); 149 } 150 h->fd = fd; 151 h->offset = offset;
|
115
| 152
|
116 cbasename = argv[0]; 117 while ((c = getopt(argc, argv, "v")) != EOF) { 118 switch (c) {
| 153 *handle = (fstyp_mod_handle_t)h; 154 return (0); 155}
|
119
| 156
|
120 case 'v': /* dump super block */ 121 vflag++; 122 break;
| 157void 158fstyp_mod_fini(fstyp_mod_handle_t handle) 159{ 160 struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle;
|
123
| 161
|
124 case '?': 125 errflag++;
| 162 if (h->attr == NULL) { 163 nvlist_free(h->attr); 164 h->attr = NULL; 165 } 166 free(h); 167} 168 169int 170fstyp_mod_ident(fstyp_mod_handle_t handle) 171{ 172 struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle; 173 174 return (is_pcfs(h)); 175} 176 177int 178fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp) 179{ 180 struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle; 181 int error; 182 183 if (h->attr == NULL) { 184 if (nvlist_alloc(&h->attr, NV_UNIQUE_NAME_TYPE, 0)) { 185 return (FSTYP_ERR_NOMEM);
|
126 }
| 186 }
|
| 187 if ((error = get_attr(h)) != 0) { 188 nvlist_free(h->attr); 189 h->attr = NULL; 190 return (error); 191 }
|
127 }
| 192 }
|
128 if (errflag || argc <= optind) { 129 usage(); 130 exit(31+1);
| 193 194 *attrp = h->attr; 195 return (0); 196} 197 198int 199fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr) 200{ 201 struct fstyp_pcfs *h = (struct fstyp_pcfs *)handle; 202 203 return (dumpfs(h, fout, ferr)); 204} 205 206 207/* 208 * Read in boot sector. Convert into host endianness where possible. 209 */ 210static int 211read_bootsec(fstyp_pcfs_t *h) 212{ 213 char buf[PC_SECSIZE]; 214 215 (void) lseek(h->fd, h->offset, SEEK_SET); 216 if (read(h->fd, buf, sizeof (buf)) != sizeof (buf)) { 217 return (FSTYP_ERR_IO);
|
131 }
| 218 }
|
132 special = argv[optind]; 133 dumpfs(special);
| |
134
| 219
|
| 220 bcopy(buf, &h->bs, sizeof (h->bs)); 221 bcopy(buf + sizeof (struct bootsec), &h->bs16, sizeof (h->bs16)); 222 bcopy(buf + sizeof (struct bootsec), &h->bs32, sizeof (h->bs32)); 223 224 h->bs.fatsec = ltohs(h->bs.fatsec); 225 h->bs.spt = ltohs(h->bs.spt); 226 h->bs.nhead = ltohs(h->bs.nhead); 227 h->bs.hiddensec = ltohi(h->bs.hiddensec); 228 h->bs.totalsec = ltohi(h->bs.totalsec); 229 230 h->bs32.f_fatlength = ltohi(h->bs32.f_fatlength); 231 h->bs32.f_flags = ltohs(h->bs32.f_flags); 232 h->bs32.f_rootcluster = ltohi(h->bs32.f_rootcluster); 233 h->bs32.f_infosector = ltohs(h->bs32.f_infosector); 234 h->bs32.f_backupboot = ltohs(h->bs32.f_backupboot); 235 236 h->bps = PC_BPSEC(h); 237
|
135 return (0); 136} 137
| 238 return (0); 239} 240
|
| 241static int 242valid_media(fstyp_pcfs_t *h) 243{ 244 switch (h->bs.mediadesriptor) { 245 case MD_FIXED: 246 case SS8SPT: 247 case DS8SPT: 248 case SS9SPT: 249 case DS9SPT: 250 case DS18SPT: 251 case DS9_15SPT: 252 return (1); 253 default: 254 return (0); 255 } 256}
|
138
| 257
|
| 258static int 259well_formed(fstyp_pcfs_t *h) 260{ 261 int fatmatch; 262 263 if (h->bs16.f_bootsig == 0x29) { 264 fatmatch = ((h->bs16.f_typestring[0] == 'F' && 265 h->bs16.f_typestring[1] == 'A' && 266 h->bs16.f_typestring[2] == 'T') && 267 (h->bs.fatsec > 0) && 268 ((PC_NSEC(h) == 0 && h->bs.totalsec > 0) || 269 PC_NSEC(h) > 0)); 270 } else if (h->bs32.f_bootsig == 0x29) { 271 fatmatch = ((h->bs32.f_typestring[0] == 'F' && 272 h->bs32.f_typestring[1] == 'A' && 273 h->bs32.f_typestring[2] == 'T') && 274 (h->bs.fatsec == 0 && h->bs32.f_fatlength > 0) && 275 ((PC_NSEC(h) == 0 && h->bs.totalsec > 0) || 276 PC_NSEC(h) > 0)); 277 } else { 278 fatmatch = (PC_NSEC(h) > 0 && h->bs.fatsec > 0); 279 } 280 281 return (fatmatch && h->bps > 0 && h->bps % 512 == 0 && 282 h->bs.spcl > 0 && PC_RESSEC(h) >= 1 && h->bs.nfat > 0); 283} 284
|
139static void
| 285static void
|
140usage(void)
| 286calculate_parameters(fstyp_pcfs_t *h)
|
141{
| 287{
|
142 (void) fprintf(stderr, gettext("pcfs usage: fstyp [-v] special\n"));
| 288 if (PC_NSEC(h) != 0) { 289 h->TotSec = PC_NSEC(h); 290 } else { 291 h->TotSec = h->bs.totalsec; 292 } 293 if (h->bs.fatsec != 0) { 294 h->FATSz = h->bs.fatsec; 295 } else { 296 h->FATSz = h->bs32.f_fatlength; 297 } 298 if ((h->bps == 0) || (h->bs.spcl == 0)) { 299 return; 300 } 301 h->RootDirSectors = 302 ((PC_NROOTENT(h) * 32) + (h->bps - 1)) / h->bps; 303 h->FirstDataSector = 304 PC_RESSEC(h) + h->bs.nfat * h->FATSz + h->RootDirSectors; 305 h->DataSec = h->TotSec - h->FirstDataSector; 306 h->CountOfClusters = h->DataSec / h->bs.spcl;
|
143} 144 145static void
| 307} 308 309static void
|
146dumpfs(char *name)
| 310determine_fattype(fstyp_pcfs_t *h)
|
147{
| 311{
|
148 unsigned char buf[DEV_BSIZE]; 149 char label[LABEL_SIZE+1]; 150 unsigned char media;
| 312 if ((h->CountOfClusters >= 4085 && h->CountOfClusters <= 4095) || 313 (h->CountOfClusters >= 65525 && h->CountOfClusters <= 65535)) { 314 h->fattype = 0; 315 } else if (h->CountOfClusters < 4085) { 316 h->fattype = 12; 317 } else if (h->CountOfClusters < 65525) { 318 h->fattype = 16; 319 } else { 320 h->fattype = 32; 321 } 322}
|
151
| 323
|
152 close(0); 153 if (open(name, 0) != 0) { 154 perror(name); 155 exit(1);
| 324static void 325get_label(fstyp_pcfs_t *h) 326{ 327 /* 328 * Use label from the boot sector by default. 329 * Can overwrite later with the one from root directory. 330 */ 331 (void) memcpy(h->volume_label, PC_LABEL_ADDR(h), PC_LABEL_SIZE); 332 h->volume_label[PC_LABEL_SIZE] = '\0'; 333 334 if (h->fattype == 0) { 335 return; 336 } else if (FSTYP_IS_32(h)) { 337 get_label_32(h); 338 } else { 339 get_label_16(h);
|
156 }
| 340 }
|
157 llseek(0, (offset_t)0, 0); 158 if (read(0, buf, sizeof (buf)) != sizeof (buf)) {
| 341}
|
159
| 342
|
160 /* 161 * As an fstyp command, this can get called for a device from 162 * any filesystem (or for that matter, a bogus device). The 163 * read() returns EINVAL when it's not a pcfs. In this case, 164 * don't print an error message. 165 */ 166 if (errno != EINVAL) { 167 perror(name);
| 343/* 344 * Get volume label from the root directory entry. 345 * In FAT12/16 the root directory is of fixed size. 346 * It immediately follows the FATs 347 */ 348static void 349get_label_16(fstyp_pcfs_t *h) 350{ 351 ulong_t FirstRootDirSecNum; 352 int secsize; 353 off_t offset; 354 uint8_t buf[PC_SECSIZE * 4]; 355 int i; 356 int nent, resid; 357 358 if ((secsize = h->bps) > sizeof (buf)) { 359 return; 360 } 361 362 FirstRootDirSecNum = PC_RESSEC(h) + h->bs.nfat * h->bs.fatsec; 363 offset = h->offset + FirstRootDirSecNum * secsize; 364 resid = PC_NROOTENT(h); 365 366 for (i = 0; i < h->RootDirSectors; i++) { 367 (void) lseek(h->fd, offset, SEEK_SET); 368 if (read(h->fd, buf, secsize) != secsize) { 369 return;
|
168 }
| 370 }
|
169 exit(1);
| 371 372 nent = secsize / sizeof (struct pcdir); 373 if (nent > resid) { 374 nent = resid; 375 } 376 if (dir_find_label(h, (struct pcdir *)buf, nent)) { 377 return; 378 } 379 380 resid -= nent; 381 offset += PC_SECSIZE;
|
170 }
| 382 }
|
| 383}
|
171
| 384
|
172 media = (unsigned char)PC_MEDIA(buf); 173 if (!valid_media(media)) 174 exit(31+1); 175 if (!well_formed(buf)) 176 exit(31+1); 177 printf("%s\n", "pcfs");
| 385/* 386 * Get volume label from the root directory entry. 387 * In FAT32 root is a usual directory, a cluster chain. 388 * It starts at BPB_RootClus. 389 */ 390static void 391get_label_32(fstyp_pcfs_t *h) 392{ 393 off_t offset; 394 int clustersize; 395 int n; 396 ulong_t FirstSectorofCluster; 397 uint8_t *buf; 398 int nent; 399 int cnt = 0;
|
178
| 400
|
179 if (!vflag) 180 exit(0);
| 401 clustersize = h->bs.spcl * h->bps; 402 if ((clustersize == 0) || (clustersize > FSTYP_MAX_CLUSTER_SIZE) || 403 ((buf = calloc(1, clustersize)) == NULL)) { 404 return; 405 }
|
181
| 406
|
182 printf("Bytes Per Sector %d\t\tSectors Per Cluster %d\n", 183 (unsigned short)PC_BPSEC(buf), (unsigned char)PC_SPC(buf)); 184 printf("Reserved Sectors %d\t\tNumber of FATs %d\n", 185 (unsigned short)PC_RESSEC(buf), (unsigned char)PC_NFAT(buf)); 186 printf("Root Dir Entries %d\t\tNumber of Sectors %d\n", 187 (unsigned short)PC_NROOTENT(buf), (unsigned short)PC_NSEC(buf)); 188 printf("Sectors Per FAT %d\t\tSectors Per Track %d\n", 189 (unsigned short)PC_SPF(buf), (unsigned short)PC_SPT(buf)); 190 printf("Number of Heads %d\t\tNumber Hidden Sectors %d\n", 191 (unsigned short)PC_NHEAD(buf), (unsigned short)PC_HIDSEC(buf)); 192 strncpy(label, PC_LAB_ADDR(buf), LABEL_SIZE); 193 label[LABEL_SIZE+1] = 0; 194 printf("Volume Label: %s\n", label); 195 printf("Drive Number: 0x%x\n", (unsigned char)PC_DRVNUM(buf)); 196 printf("Media Type: 0x%x ", media);
| 407 for (n = h->bs32.f_rootcluster; n != 0; n = next_cluster_32(h, n)) { 408 FirstSectorofCluster = 409 (n - 2) * h->bs.spcl + h->FirstDataSector; 410 offset = h->offset + FirstSectorofCluster * h->bps; 411 (void) lseek(h->fd, offset, SEEK_SET); 412 if (read(h->fd, buf, clustersize) != clustersize) { 413 break; 414 }
|
197
| 415
|
198 switch (media) {
| 416 nent = clustersize / sizeof (struct pcdir); 417 if (dir_find_label(h, (struct pcdir *)buf, nent)) { 418 break; 419 } 420 421 if (++cnt > FSTYP_MAX_DIR_SIZE / clustersize) { 422 break; 423 } 424 } 425 426 free(buf); 427} 428 429/* 430 * Get a FAT entry pointing to the next file cluster 431 */ 432int 433next_cluster_32(fstyp_pcfs_t *h, int n) 434{ 435 uint8_t buf[PC_SECSIZE]; 436 ulong_t ThisFATSecNum; 437 ulong_t ThisFATEntOffset; 438 off_t offset; 439 uint32_t val; 440 int next = 0; 441 442 ThisFATSecNum = PC_RESSEC(h) + (n * 4) / h->bps; 443 ThisFATEntOffset = (n * 4) % h->bps; 444 offset = h->offset + ThisFATSecNum * h->bps; 445 446 (void) lseek(h->fd, offset, SEEK_SET); 447 if (read(h->fd, buf, sizeof (buf)) == sizeof (buf)) { 448 val = buf[ThisFATEntOffset] & 0x0fffffff; 449 next = ltohi(val); 450 } 451 452 return (next); 453} 454 455/* 456 * Given an array of pcdir structs, find one containing volume label. 457 */ 458static boolean_t 459dir_find_label(fstyp_pcfs_t *h, struct pcdir *d, int nent) 460{ 461 int i; 462 463 for (i = 0; i < nent; i++, d++) { 464 if ((d->pcd_filename[0] != PCD_UNUSED) && 465 (d->pcd_filename[0] != PCD_ERASED) && 466 ((d->pcd_attr & (PCA_LABEL | PCA_DIR)) == PCA_LABEL) && 467 (d->un.pcd_scluster_hi == 0) && 468 (d->pcd_scluster_lo == 0)) { 469 (void) memcpy(h->volume_label, d->pcd_filename, 470 PC_LABEL_SIZE); 471 h->volume_label[PC_LABEL_SIZE] = '\0'; 472 return (B_TRUE); 473 } 474 } 475 return (B_FALSE); 476} 477 478static int 479is_pcfs(fstyp_pcfs_t *h) 480{ 481 int error; 482 483 if ((error = read_bootsec(h)) != 0) { 484 return (error); 485 } 486 if (!valid_media(h)) { 487 return (FSTYP_ERR_NO_MATCH); 488 } 489 if (!well_formed(h)) { 490 return (FSTYP_ERR_NO_MATCH); 491 } 492 493 calculate_parameters(h); 494 determine_fattype(h); 495 get_label(h); 496 497 return (0); 498} 499 500/* ARGSUSED */ 501static int 502dumpfs(fstyp_pcfs_t *h, FILE *fout, FILE *ferr) 503{ 504 (void) fprintf(fout, 505 "Bytes Per Sector %d\t\tSectors Per Cluster %d\n", 506 h->bps, h->bs.spcl); 507 (void) fprintf(fout, 508 "Reserved Sectors %d\t\tNumber of FATs %d\n", 509 (unsigned short)PC_RESSEC(h), h->bs.nfat); 510 (void) fprintf(fout, 511 "Root Dir Entries %d\t\tNumber of Sectors %d\n", 512 (unsigned short)PC_NROOTENT(h), (unsigned short)PC_NSEC(h)); 513 (void) fprintf(fout, 514 "Sectors Per FAT %d\t\tSectors Per Track %d\n", 515 h->bs.fatsec, h->bs.spt); 516 (void) fprintf(fout, 517 "Number of Heads %d\t\tNumber Hidden Sectors %d\n", 518 h->bs.nhead, h->bs.hiddensec); 519 (void) fprintf(fout, "Volume ID: 0x%x\n", PC_VOLID(h)); 520 (void) fprintf(fout, "Volume Label: %s\n", h->volume_label); 521 (void) fprintf(fout, "Drive Number: 0x%x\n", PC_DRVNUM(h)); 522 (void) fprintf(fout, "Media Type: 0x%x ", h->bs.mediadesriptor); 523 524 switch (h->bs.mediadesriptor) {
|
199 case MD_FIXED:
| 525 case MD_FIXED:
|
200 printf("\"Fixed\" Disk\n");
| 526 (void) fprintf(fout, "\"Fixed\" Disk\n");
|
201 break; 202 case SS8SPT:
| 527 break; 528 case SS8SPT:
|
203 printf("Single Sided, 8 Sectors Per Track\n");
| 529 (void) fprintf(fout, "Single Sided, 8 Sectors Per Track\n");
|
204 break; 205 case DS8SPT:
| 530 break; 531 case DS8SPT:
|
206 printf("Double Sided, 8 Sectors Per Track\n");
| 532 (void) fprintf(fout, "Double Sided, 8 Sectors Per Track\n");
|
207 break; 208 case SS9SPT:
| 533 break; 534 case SS9SPT:
|
209 printf("Single Sided, 9 Sectors Per Track\n");
| 535 (void) fprintf(fout, "Single Sided, 9 Sectors Per Track\n");
|
210 break; 211 case DS9SPT:
| 536 break; 537 case DS9SPT:
|
212 printf("Double Sided, 9 Sectors Per Track\n");
| 538 (void) fprintf(fout, "Double Sided, 9 Sectors Per Track\n");
|
213 break; 214 case DS18SPT:
| 539 break; 540 case DS18SPT:
|
215 printf("Double Sided, 18 Sectors Per Track\n");
| 541 (void) fprintf(fout, "Double Sided, 18 Sectors Per Track\n");
|
216 break; 217 case DS9_15SPT:
| 542 break; 543 case DS9_15SPT:
|
218 printf("Double Sided, 9-15 Sectors Per Track\n");
| 544 (void) fprintf(fout, "Double Sided, 9-15 Sectors Per Track\n");
|
219 break; 220 default:
| 545 break; 546 default:
|
221 printf("Unknown Media Type\n");
| 547 (void) fprintf(fout, "Unknown Media Type\n");
|
222 } 223
| 548 } 549
|
224 close(0); 225 exit(0);
| 550 return (0);
|
226} 227
| 551} 552
|
228static int 229valid_media(unsigned char media_type) 230{ 231 switch (media_type) {
| 553#define ADD_STRING(h, name, value) \ 554 if (nvlist_add_string(h->attr, name, value) != 0) { \ 555 return (FSTYP_ERR_NOMEM); \ 556 }
|
232
| 557
|
233 case MD_FIXED: 234 case SS8SPT: 235 case DS8SPT: 236 case SS9SPT: 237 case DS9SPT: 238 case DS18SPT: 239 case DS9_15SPT: 240 return (1); 241 default: 242 return (0);
| 558#define ADD_UINT32(h, name, value) \ 559 if (nvlist_add_uint32(h->attr, name, value) != 0) { \ 560 return (FSTYP_ERR_NOMEM); \
|
243 }
| 561 }
|
244}
| |
245
| 562
|
246int 247well_formed(unsigned char bs[])
| 563#define ADD_UINT64(h, name, value) \ 564 if (nvlist_add_uint64(h->attr, name, value) != 0) { \ 565 return (FSTYP_ERR_NOMEM); \ 566 } 567 568#define ADD_BOOL(h, name, value) \ 569 if (nvlist_add_boolean_value(h->attr, name, value) != 0) { \ 570 return (FSTYP_ERR_NOMEM); \ 571 } 572 573static int 574get_attr(fstyp_pcfs_t *h)
|
248{
| 575{
|
249 int fatmatch;
| 576 char s[64];
|
250
| 577
|
251 if (PC_EXTSIG(bs)) { 252 fatmatch = ((bs[PCFS_TYPESTRING_OFFSET16] == 'F' && 253 bs[PCFS_TYPESTRING_OFFSET16 + 1] == 'A' && 254 bs[PCFS_TYPESTRING_OFFSET16 + 2] == 'T') && 255 (PC_SPF(bs) > 0) && 256 ((PC_NSEC(bs) == 0 && PC_BIGNSEC(bs) > 0) || 257 PC_NSEC(bs) > 0)); 258 } else if (PC_EXTSIG32(bs)) { 259 fatmatch = ((bs[PCFS_TYPESTRING_OFFSET32] == 'F' && 260 bs[PCFS_TYPESTRING_OFFSET32 + 1] == 'A' && 261 bs[PCFS_TYPESTRING_OFFSET32 + 2] == 'T') && 262 (PC_SPF(bs) == 0 && PC_BIGSPF(bs) > 0) && 263 ((PC_NSEC(bs) == 0 && PC_BIGNSEC(bs) > 0) || 264 PC_NSEC(bs) > 0)); 265 } else { 266 fatmatch = (PC_NSEC(bs) > 0 && PC_SPF(bs) > 0);
| 578 ADD_UINT32(h, "bytes_per_sector", h->bps); 579 ADD_UINT32(h, "sectors_per_cluster", h->bs.spcl); 580 ADD_UINT32(h, "reserved_sectors", PC_RESSEC(h)); 581 ADD_UINT32(h, "fats", h->bs.nfat); 582 ADD_UINT32(h, "root_entry_count", PC_NROOTENT(h)); 583 ADD_UINT32(h, "total_sectors_16", PC_NSEC(h)); 584 ADD_UINT32(h, "media", h->bs.mediadesriptor); 585 ADD_UINT32(h, "fat_size_16", h->bs.fatsec); 586 ADD_UINT32(h, "sectors_per_track", h->bs.spt); 587 ADD_UINT32(h, "heads", h->bs.nhead); 588 ADD_UINT32(h, "hidden_sectors", h->bs.hiddensec); 589 ADD_UINT32(h, "total_sectors_32", h->bs.totalsec); 590 ADD_UINT32(h, "drive_number", PC_DRVNUM(h)); 591 ADD_UINT32(h, "volume_id", PC_VOLID(h)); 592 ADD_STRING(h, "volume_label", h->volume_label); 593 if (FSTYP_IS_32(h)) { 594 ADD_UINT32(h, "fat_size_32", h->bs32.f_fatlength);
|
267 }
| 595 }
|
| 596 ADD_UINT32(h, "total_sectors", h->TotSec); 597 ADD_UINT32(h, "fat_size", h->FATSz); 598 ADD_UINT32(h, "count_of_clusters", h->CountOfClusters); 599 ADD_UINT32(h, "fat_entry_size", h->fattype);
|
268
| 600
|
269 return (fatmatch && PC_BPSEC(bs) > 0 && PC_BPSEC(bs) % 512 == 0 && 270 PC_SPC(bs) > 0 && PC_RESSEC(bs) >= 1 && PC_NFAT(bs) > 0);
| 601 ADD_BOOL(h, "gen_clean", B_TRUE); 602 if (PC_VOLID(a) != 0) { 603 (void) snprintf(s, sizeof (s), "%08x", PC_VOLID(a)); 604 ADD_STRING(h, "gen_guid", s); 605 } 606 (void) snprintf(s, sizeof (s), "%d", h->fattype); 607 ADD_STRING(h, "gen_version", s); 608 ADD_STRING(h, "gen_volume_label", h->volume_label); 609 610 return (0);
|
271}
| 611}
|