1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Basic file system reading code for standalone I/O system. 31*0Sstevel@tonic-gate * Simulates a primitive UNIX I/O system (read(), write(), open(), etc). 32*0Sstevel@tonic-gate * Does not support writes. 33*0Sstevel@tonic-gate */ 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate /* 36*0Sstevel@tonic-gate * WARNING: 37*0Sstevel@tonic-gate * This is currently used by installgrub for creating bootable floppy. 38*0Sstevel@tonic-gate * The special part is diskread_callback/fileread_callback for gathering 39*0Sstevel@tonic-gate * fileblock list. 40*0Sstevel@tonic-gate */ 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate #include <sys/param.h> 43*0Sstevel@tonic-gate #include <sys/sysmacros.h> 44*0Sstevel@tonic-gate #include <sys/vnode.h> 45*0Sstevel@tonic-gate #include <sys/fs/pc_label.h> 46*0Sstevel@tonic-gate #include <sys/bootvfs.h> 47*0Sstevel@tonic-gate #include <sys/filep.h> 48*0Sstevel@tonic-gate #include "pcfilep.h" 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate #if defined(_BOOT) 51*0Sstevel@tonic-gate #include "../common/util.h" 52*0Sstevel@tonic-gate #elif defined(_KERNEL) 53*0Sstevel@tonic-gate #include <sys/sunddi.h> 54*0Sstevel@tonic-gate #else 55*0Sstevel@tonic-gate #include <stdio.h> 56*0Sstevel@tonic-gate #include <strings.h> 57*0Sstevel@tonic-gate #include <ctype.h> 58*0Sstevel@tonic-gate #endif 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate #if defined(_BOOT) 61*0Sstevel@tonic-gate #define dprintf if (bootrd_debug) printf 62*0Sstevel@tonic-gate #elif defined(_KERNEL) 63*0Sstevel@tonic-gate #define printf kobj_printf 64*0Sstevel@tonic-gate #define dprintf if (bootrd_debug) kobj_printf 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate /* PRINTLIKE */ 67*0Sstevel@tonic-gate extern void kobj_printf(char *, ...); 68*0Sstevel@tonic-gate #else 69*0Sstevel@tonic-gate #define dprintf if (bootrd_debug) printf 70*0Sstevel@tonic-gate #endif 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate #define FI_STARTCLUST(fp) (*(ushort_t *)(fp)->fi_buf) 73*0Sstevel@tonic-gate #define FI_LENGTH(fp) (*(long *)((fp)->fi_buf + 4)) 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate extern int bootrd_debug; 76*0Sstevel@tonic-gate extern void *bkmem_alloc(size_t); 77*0Sstevel@tonic-gate extern void bkmem_free(void *, size_t); 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate /* 80*0Sstevel@tonic-gate * NOTE: The fileread_callback is set by the calling program 81*0Sstevel@tonic-gate * during a file read. diskread_callback is set to fileread_callback 82*0Sstevel@tonic-gate * only if reading a file block. It needs to be NULL while reading 83*0Sstevel@tonic-gate * cluster blocks. 84*0Sstevel@tonic-gate */ 85*0Sstevel@tonic-gate extern int (*diskread_callback)(int, int); 86*0Sstevel@tonic-gate extern int (*fileread_callback)(int, int); 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate /* 89*0Sstevel@tonic-gate * Local prototypes 90*0Sstevel@tonic-gate */ 91*0Sstevel@tonic-gate static int lookuppn(char *, _dir_entry_p); 92*0Sstevel@tonic-gate static fileid_t *find_fp(int); 93*0Sstevel@tonic-gate static void *readblock(int, int); 94*0Sstevel@tonic-gate static int fat_map(int, int); 95*0Sstevel@tonic-gate static int cluster_valid(long, int); 96*0Sstevel@tonic-gate static int fat_ctodb(int, int); 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate static int bpcfs_mountroot(char *str); 99*0Sstevel@tonic-gate static int bpcfs_unmountroot(void); 100*0Sstevel@tonic-gate static int bpcfs_open(char *str, int flags); 101*0Sstevel@tonic-gate static int bpcfs_close(int fd); 102*0Sstevel@tonic-gate static void bpcfs_closeall(void); 103*0Sstevel@tonic-gate static ssize_t bpcfs_read(int fdesc, char *buf, size_t count); 104*0Sstevel@tonic-gate static off_t bpcfs_lseek(int fdesc, off_t addr, int whence); 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate static fileid_t *head; 107*0Sstevel@tonic-gate static _fat_controller_p pcfsp; 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate /* cache the cluster */ 110*0Sstevel@tonic-gate static int nsec_cache; 111*0Sstevel@tonic-gate static int nsec_start; 112*0Sstevel@tonic-gate static char *cluster_cache; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate /*ARGSUSED*/ 115*0Sstevel@tonic-gate static int 116*0Sstevel@tonic-gate bpcfs_mountroot(char *str) 117*0Sstevel@tonic-gate { 118*0Sstevel@tonic-gate int ncluster; 119*0Sstevel@tonic-gate if (pcfsp != NULL) 120*0Sstevel@tonic-gate return (0); /* already mounted */ 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate pcfsp = bkmem_alloc(sizeof (_fat_controller_t)); 123*0Sstevel@tonic-gate head = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 124*0Sstevel@tonic-gate head->fi_back = head->fi_forw = head; 125*0Sstevel@tonic-gate head->fi_filedes = 0; 126*0Sstevel@tonic-gate head->fi_taken = 0; 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /* read of first floppy sector */ 129*0Sstevel@tonic-gate head->fi_blocknum = 0; 130*0Sstevel@tonic-gate head->fi_count = SECSIZ; 131*0Sstevel@tonic-gate head->fi_memp = (caddr_t)pcfsp->f_sector; 132*0Sstevel@tonic-gate if (diskread(head)) { 133*0Sstevel@tonic-gate printf("failed to read first sector\n"); 134*0Sstevel@tonic-gate bkmem_free(pcfsp, sizeof (*pcfsp)); 135*0Sstevel@tonic-gate pcfsp = NULL; 136*0Sstevel@tonic-gate return (-1); 137*0Sstevel@tonic-gate } 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate if (pcfsp->f_bpb.bs_spc == 0) { 140*0Sstevel@tonic-gate printf("invalid bios paramet block\n"); 141*0Sstevel@tonic-gate return (-1); 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate pcfsp->f_rootsec = 145*0Sstevel@tonic-gate (pcfsp->f_bpb.bs_num_fats * ltohs(pcfsp->f_bpb.bs_spf)) + 146*0Sstevel@tonic-gate ltohs(pcfsp->f_bpb.bs_resv_sectors); 147*0Sstevel@tonic-gate pcfsp->f_rootlen = 148*0Sstevel@tonic-gate ltohs(pcfsp->f_bpb.bs_num_root_entries) * 149*0Sstevel@tonic-gate sizeof (_dir_entry_t) / SECSIZ; 150*0Sstevel@tonic-gate pcfsp->f_adjust = 0; 151*0Sstevel@tonic-gate pcfsp->f_dclust = CLUSTER_ROOTDIR; 152*0Sstevel@tonic-gate pcfsp->f_filesec = pcfsp->f_rootsec + pcfsp->f_rootlen; 153*0Sstevel@tonic-gate pcfsp->f_nxtfree = CLUSTER_FIRST; 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate /* figure out the number of clusters in this partition */ 156*0Sstevel@tonic-gate ncluster = (((ulong_t)ltohs(pcfsp->f_bpb.bs_siv) ? 157*0Sstevel@tonic-gate (ulong_t)ltohs(pcfsp->f_bpb.bs_siv) : 158*0Sstevel@tonic-gate (ulong_t)ltohi(pcfsp->f_bpb.bs_siv)) - 159*0Sstevel@tonic-gate pcfsp->f_filesec) / (ulong_t)pcfsp->f_bpb.bs_spc; 160*0Sstevel@tonic-gate pcfsp->f_16bit = ncluster >= CLUSTER_MAX_12; 161*0Sstevel@tonic-gate pcfsp->f_ncluster = ncluster; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate /* cache the cluster */ 164*0Sstevel@tonic-gate if (pcfsp->f_16bit) 165*0Sstevel@tonic-gate nsec_cache = (((ncluster << 1) + 511) >> 9); 166*0Sstevel@tonic-gate else 167*0Sstevel@tonic-gate nsec_cache = (ncluster + ((ncluster + 1) >> 1) + 511) >> 9; 168*0Sstevel@tonic-gate cluster_cache = bkmem_alloc(nsec_cache * SECSIZ); 169*0Sstevel@tonic-gate if (cluster_cache == NULL) { 170*0Sstevel@tonic-gate printf("bpcfs_mountroot: out of memory\n"); 171*0Sstevel@tonic-gate bkmem_free(pcfsp, sizeof (*pcfsp)); 172*0Sstevel@tonic-gate pcfsp = NULL; 173*0Sstevel@tonic-gate return (-1); 174*0Sstevel@tonic-gate } 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate head->fi_blocknum = nsec_start = 177*0Sstevel@tonic-gate ltohs(pcfsp->f_bpb.bs_resv_sectors) + pcfsp->f_adjust; 178*0Sstevel@tonic-gate head->fi_count = nsec_cache * SECSIZ; 179*0Sstevel@tonic-gate head->fi_memp = cluster_cache; 180*0Sstevel@tonic-gate if (diskread(head)) { 181*0Sstevel@tonic-gate printf("bpcfs_mountroot: failed to read cluster\n"); 182*0Sstevel@tonic-gate bkmem_free(pcfsp, sizeof (*pcfsp)); 183*0Sstevel@tonic-gate pcfsp = NULL; 184*0Sstevel@tonic-gate return (-1); 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate dprintf("read cluster sectors %d starting at %d\n", 187*0Sstevel@tonic-gate nsec_cache, nsec_start); 188*0Sstevel@tonic-gate return (0); 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate static int 192*0Sstevel@tonic-gate bpcfs_unmountroot(void) 193*0Sstevel@tonic-gate { 194*0Sstevel@tonic-gate if (pcfsp == NULL) 195*0Sstevel@tonic-gate return (-1); 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate (void) bpcfs_closeall(); 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate return (0); 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate /* 203*0Sstevel@tonic-gate * Open a file. 204*0Sstevel@tonic-gate */ 205*0Sstevel@tonic-gate /*ARGSUSED*/ 206*0Sstevel@tonic-gate int 207*0Sstevel@tonic-gate bpcfs_open(char *str, int flags) 208*0Sstevel@tonic-gate { 209*0Sstevel@tonic-gate static int filedes = 1; 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate fileid_t *filep; 212*0Sstevel@tonic-gate _dir_entry_t d; 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate dprintf("open %s\n", str); 215*0Sstevel@tonic-gate filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t)); 216*0Sstevel@tonic-gate filep->fi_back = head->fi_back; 217*0Sstevel@tonic-gate filep->fi_forw = head; 218*0Sstevel@tonic-gate head->fi_back->fi_forw = filep; 219*0Sstevel@tonic-gate head->fi_back = filep; 220*0Sstevel@tonic-gate filep->fi_filedes = filedes++; 221*0Sstevel@tonic-gate filep->fi_taken = 1; 222*0Sstevel@tonic-gate filep->fi_path = (char *)bkmem_alloc(strlen(str) + 1); 223*0Sstevel@tonic-gate (void) strcpy(filep->fi_path, str); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate if (lookuppn(str, &d)) { 226*0Sstevel@tonic-gate (void) bpcfs_close(filep->fi_filedes); 227*0Sstevel@tonic-gate return (-1); 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate filep->fi_offset = 0; 231*0Sstevel@tonic-gate FI_STARTCLUST(filep) = d.d_cluster; 232*0Sstevel@tonic-gate FI_LENGTH(filep) = d.d_size; 233*0Sstevel@tonic-gate dprintf("file %s size = %ld\n", str, d.d_size); 234*0Sstevel@tonic-gate return (filep->fi_filedes); 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate int 238*0Sstevel@tonic-gate bpcfs_close(int fd) 239*0Sstevel@tonic-gate { 240*0Sstevel@tonic-gate fileid_t *filep; 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate dprintf("close %d\n", fd); 243*0Sstevel@tonic-gate if (!(filep = find_fp(fd))) 244*0Sstevel@tonic-gate return (-1); 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate if (filep->fi_taken == 0 || filep == head) { 247*0Sstevel@tonic-gate printf("File descripter %d no allocated!\n", fd); 248*0Sstevel@tonic-gate return (-1); 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* unlink and deallocate node */ 252*0Sstevel@tonic-gate filep->fi_forw->fi_back = filep->fi_back; 253*0Sstevel@tonic-gate filep->fi_back->fi_forw = filep->fi_forw; 254*0Sstevel@tonic-gate bkmem_free(filep->fi_path, strlen(filep->fi_path) + 1); 255*0Sstevel@tonic-gate bkmem_free((char *)filep, sizeof (fileid_t)); 256*0Sstevel@tonic-gate dprintf("close done\n"); 257*0Sstevel@tonic-gate return (0); 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate static void 261*0Sstevel@tonic-gate bpcfs_closeall(void) 262*0Sstevel@tonic-gate { 263*0Sstevel@tonic-gate fileid_t *filep; 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate while ((filep = head->fi_forw) != head) 266*0Sstevel@tonic-gate if (filep->fi_taken && bpcfs_close(filep->fi_filedes)) 267*0Sstevel@tonic-gate printf("Filesystem may be inconsistent.\n"); 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate bkmem_free(pcfsp, sizeof (*pcfsp)); 270*0Sstevel@tonic-gate bkmem_free(head, sizeof (fileid_t)); 271*0Sstevel@tonic-gate pcfsp = NULL; 272*0Sstevel@tonic-gate head = NULL; 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate static ssize_t 276*0Sstevel@tonic-gate bpcfs_read(int fd, caddr_t b, size_t c) 277*0Sstevel@tonic-gate { 278*0Sstevel@tonic-gate ulong_t sector; 279*0Sstevel@tonic-gate uint_t count = 0, xfer, i; 280*0Sstevel@tonic-gate char *block; 281*0Sstevel@tonic-gate ulong_t off, blk; 282*0Sstevel@tonic-gate int rd, spc; 283*0Sstevel@tonic-gate fileid_t *fp; 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate dprintf("bpcfs_read: fd = %d, buf = %p, size = %d\n", 286*0Sstevel@tonic-gate fd, (void *)b, c); 287*0Sstevel@tonic-gate fp = find_fp(fd); 288*0Sstevel@tonic-gate if (fp == NULL) { 289*0Sstevel@tonic-gate printf("invalid file descriptor %d\n", fd); 290*0Sstevel@tonic-gate return (-1); 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate spc = pcfsp->f_bpb.bs_spc; 294*0Sstevel@tonic-gate off = fp->fi_offset; 295*0Sstevel@tonic-gate blk = FI_STARTCLUST(fp); 296*0Sstevel@tonic-gate rd = blk == CLUSTER_ROOTDIR ? 1 : 0; 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate spc = pcfsp->f_bpb.bs_spc; 299*0Sstevel@tonic-gate off = fp->fi_offset; 300*0Sstevel@tonic-gate blk = FI_STARTCLUST(fp); 301*0Sstevel@tonic-gate rd = (blk == CLUSTER_ROOTDIR) ? 1 : 0; 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate if ((c = MIN(FI_LENGTH(fp) - off, c)) == 0) 304*0Sstevel@tonic-gate return (0); 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate while (off >= pcfsp->f_bpb.bs_spc * SECSIZ) { 307*0Sstevel@tonic-gate blk = fat_map(blk, rd); 308*0Sstevel@tonic-gate off -= pcfsp->f_bpb.bs_spc * SECSIZ; 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate if (!cluster_valid(blk, rd)) { 311*0Sstevel@tonic-gate printf("bpcfs_read: invalid cluster: %ld, %d\n", 312*0Sstevel@tonic-gate blk, rd); 313*0Sstevel@tonic-gate return (-1); 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate while (count < c) { 318*0Sstevel@tonic-gate sector = fat_ctodb(blk, rd); 319*0Sstevel@tonic-gate diskread_callback = fileread_callback; 320*0Sstevel@tonic-gate for (i = ((off / SECSIZ) % pcfsp->f_bpb.bs_spc); i < spc; i++) { 321*0Sstevel@tonic-gate xfer = MIN(SECSIZ - (off % SECSIZ), c - count); 322*0Sstevel@tonic-gate if (xfer == 0) 323*0Sstevel@tonic-gate break; /* last sector done */ 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate block = (char *)readblock(sector + i, 1); 326*0Sstevel@tonic-gate if (block == NULL) { 327*0Sstevel@tonic-gate return (-1); 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate dprintf("bpcfs_read: read %d bytes\n", xfer); 330*0Sstevel@tonic-gate if (diskread_callback == NULL) 331*0Sstevel@tonic-gate (void) bcopy(&block[off % SECSIZ], b, xfer); 332*0Sstevel@tonic-gate count += xfer; 333*0Sstevel@tonic-gate off += xfer; 334*0Sstevel@tonic-gate b += xfer; 335*0Sstevel@tonic-gate } 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate diskread_callback = NULL; 338*0Sstevel@tonic-gate if (count < c) { 339*0Sstevel@tonic-gate blk = fat_map(blk, rd); 340*0Sstevel@tonic-gate if (!cluster_valid(blk, rd)) { 341*0Sstevel@tonic-gate printf("bpcfs_read: invalid cluster: %ld, %d\n", 342*0Sstevel@tonic-gate blk, rd); 343*0Sstevel@tonic-gate break; 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate fp->fi_offset += count; 349*0Sstevel@tonic-gate return (count); 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate /* 353*0Sstevel@tonic-gate * This version of seek() only performs absolute seeks (whence == 0). 354*0Sstevel@tonic-gate */ 355*0Sstevel@tonic-gate static off_t 356*0Sstevel@tonic-gate bpcfs_lseek(int fd, off_t addr, int whence) 357*0Sstevel@tonic-gate { 358*0Sstevel@tonic-gate fileid_t *filep; 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate dprintf("lseek %d, off = %lx\n", fd, addr); 361*0Sstevel@tonic-gate if (!(filep = find_fp(fd))) 362*0Sstevel@tonic-gate return (-1); 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate switch (whence) { 365*0Sstevel@tonic-gate case SEEK_CUR: 366*0Sstevel@tonic-gate filep->fi_offset += addr; 367*0Sstevel@tonic-gate break; 368*0Sstevel@tonic-gate case SEEK_SET: 369*0Sstevel@tonic-gate filep->fi_offset = addr; 370*0Sstevel@tonic-gate break; 371*0Sstevel@tonic-gate default: 372*0Sstevel@tonic-gate case SEEK_END: 373*0Sstevel@tonic-gate printf("lseek(): invalid whence value %d\n", whence); 374*0Sstevel@tonic-gate break; 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate filep->fi_blocknum = addr / DEV_BSIZE; 378*0Sstevel@tonic-gate filep->fi_count = 0; 379*0Sstevel@tonic-gate return (0); 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate static fileid_t * 383*0Sstevel@tonic-gate find_fp(int fd) 384*0Sstevel@tonic-gate { 385*0Sstevel@tonic-gate fileid_t *filep = head; 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate if (fd >= 0) { 388*0Sstevel@tonic-gate while ((filep = filep->fi_forw) != head) 389*0Sstevel@tonic-gate if (fd == filep->fi_filedes) 390*0Sstevel@tonic-gate return (filep->fi_taken ? filep : 0); 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate return (0); 394*0Sstevel@tonic-gate } 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate static int 397*0Sstevel@tonic-gate cluster_valid(long c, int rd) 398*0Sstevel@tonic-gate { 399*0Sstevel@tonic-gate return ((rd && (c == 0)) ? 1 : (c >= CLUSTER_RES_16_0 ? 0 : c)); 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate static int 403*0Sstevel@tonic-gate fat_ctodb(int blk, int r) 404*0Sstevel@tonic-gate { 405*0Sstevel@tonic-gate uint_t s; 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate s = r ? blk + pcfsp->f_rootsec + pcfsp->f_adjust : 408*0Sstevel@tonic-gate ((blk - 2) * pcfsp->f_bpb.bs_spc) + 409*0Sstevel@tonic-gate pcfsp->f_filesec + pcfsp->f_adjust; 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate return (s); 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate static int 415*0Sstevel@tonic-gate fat_map(int blk, int rootdir) 416*0Sstevel@tonic-gate { 417*0Sstevel@tonic-gate ulong_t sectn, fat_index; 418*0Sstevel@tonic-gate uchar_t *fp; 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate if (rootdir) { 421*0Sstevel@tonic-gate return (blk > pcfsp->f_rootlen ? CLUSTER_EOF : blk + 1); 422*0Sstevel@tonic-gate } 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate /* ---- Find out what sector this cluster is in ---- */ 425*0Sstevel@tonic-gate fat_index = (pcfsp->f_16bit) ? ((ulong_t)blk << 1) : 426*0Sstevel@tonic-gate ((ulong_t)blk + ((uint_t)blk >> 1)); 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate sectn = (fat_index / SECSIZ) + ltohs(pcfsp->f_bpb.bs_resv_sectors) 429*0Sstevel@tonic-gate + pcfsp->f_adjust; 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate /* 432*0Sstevel@tonic-gate * Read two sectors so that if our fat_index points at the last byte 433*0Sstevel@tonic-gate * byte we'll have the data needed. This is only a problem for fat12 434*0Sstevel@tonic-gate * entries. 435*0Sstevel@tonic-gate */ 436*0Sstevel@tonic-gate if (!(fp = (uchar_t *)readblock(sectn, 2))) { 437*0Sstevel@tonic-gate printf("fat_map: bad cluster\n"); 438*0Sstevel@tonic-gate return (CLUSTER_BAD_16); 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate fp += (fat_index % SECSIZ); 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate if (pcfsp->f_16bit) 444*0Sstevel@tonic-gate blk = fp[0] | (fp[1] << 8); 445*0Sstevel@tonic-gate else { 446*0Sstevel@tonic-gate if (blk & 1) 447*0Sstevel@tonic-gate blk = ((fp[0] >> 4) & 0xf) | (fp[1] << 4); 448*0Sstevel@tonic-gate else 449*0Sstevel@tonic-gate blk = ((fp[1] & 0xf) << 8) | fp[0]; 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate /* 452*0Sstevel@tonic-gate * This makes compares easier because we can just compare 453*0Sstevel@tonic-gate * against one value instead of two. 454*0Sstevel@tonic-gate */ 455*0Sstevel@tonic-gate if (blk >= CLUSTER_RES_12_0) 456*0Sstevel@tonic-gate blk |= CLUSTER_RES_16_0; 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate return (blk); 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate static int 462*0Sstevel@tonic-gate namecmp(char *pn, char *dn, int cs) 463*0Sstevel@tonic-gate { 464*0Sstevel@tonic-gate dprintf("namecmp %s, %s, len = %d\n", pn, dn, cs); 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate /* starting char must match */ 467*0Sstevel@tonic-gate while (*pn && *dn) { 468*0Sstevel@tonic-gate --cs; 469*0Sstevel@tonic-gate if (toupper(*pn++) != toupper(*dn++)) 470*0Sstevel@tonic-gate return (1); 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate dprintf("namecmp: cs = %d\n", cs); 474*0Sstevel@tonic-gate /* remainder should be either ~# or all spaces */ 475*0Sstevel@tonic-gate if (cs > 0 && *dn == '~') 476*0Sstevel@tonic-gate return (0); 477*0Sstevel@tonic-gate while (cs > 0) { 478*0Sstevel@tonic-gate if (*dn++ != ' ') 479*0Sstevel@tonic-gate return (1); 480*0Sstevel@tonic-gate --cs; 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate return (0); 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate static int 486*0Sstevel@tonic-gate dircmp(char *name, char *d_name, char *d_ext) 487*0Sstevel@tonic-gate { 488*0Sstevel@tonic-gate int ret; 489*0Sstevel@tonic-gate char *sep, *ext; 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate sep = (char *)strchr(name, '.'); 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate if (sep) { 494*0Sstevel@tonic-gate *sep = '\0'; 495*0Sstevel@tonic-gate ext = sep + 1; 496*0Sstevel@tonic-gate } else 497*0Sstevel@tonic-gate ext = " "; 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate if (namecmp(name, d_name, NAMESIZ) || namecmp(ext, d_ext, EXTSIZ)) 500*0Sstevel@tonic-gate ret = 1; 501*0Sstevel@tonic-gate else 502*0Sstevel@tonic-gate ret = 0; 503*0Sstevel@tonic-gate if (sep) 504*0Sstevel@tonic-gate *sep = '.'; 505*0Sstevel@tonic-gate return (ret); 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate static int 509*0Sstevel@tonic-gate lookup(char *n, _dir_entry_p dp, ulong_t dir_blk) 510*0Sstevel@tonic-gate { 511*0Sstevel@tonic-gate int spc = pcfsp->f_bpb.bs_spc; 512*0Sstevel@tonic-gate int rd = (dir_blk == CLUSTER_ROOTDIR ? 1 : 0); 513*0Sstevel@tonic-gate _dir_entry_p dxp; 514*0Sstevel@tonic-gate int j, sector; 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate dprintf("lookup: name = %s\n", n); 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate while (cluster_valid(dir_blk, rd)) { 519*0Sstevel@tonic-gate sector = fat_ctodb(dir_blk, rd); 520*0Sstevel@tonic-gate dxp = readblock(sector, 1); /* read one sector */ 521*0Sstevel@tonic-gate if (dxp == NULL) 522*0Sstevel@tonic-gate return (0); 523*0Sstevel@tonic-gate for (j = 0; j < DIRENTS * spc; j++, dxp++) { 524*0Sstevel@tonic-gate dprintf("lookup: dir entry %s.%s;\n", 525*0Sstevel@tonic-gate dxp->d_name, dxp->d_ext); 526*0Sstevel@tonic-gate if (dxp->d_name[0] == 0) 527*0Sstevel@tonic-gate return (0); 528*0Sstevel@tonic-gate if ((uchar_t)dxp->d_name[0] != 0xE5 && 529*0Sstevel@tonic-gate (dxp->d_attr & (DE_LABEL|DE_HIDDEN)) == 0 && 530*0Sstevel@tonic-gate dircmp(n, dxp->d_name, dxp->d_ext) == 0) { 531*0Sstevel@tonic-gate dprintf("lookup: match found\n"); 532*0Sstevel@tonic-gate (void) bcopy(dxp, dp, sizeof (*dp)); 533*0Sstevel@tonic-gate return (1); 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate /* next cluster */ 537*0Sstevel@tonic-gate dir_blk = fat_map(dir_blk, rd); 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate return (0); 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate static int 544*0Sstevel@tonic-gate lookuppn(char *n, _dir_entry_p dp) 545*0Sstevel@tonic-gate { 546*0Sstevel@tonic-gate long dir_blk; 547*0Sstevel@tonic-gate char name[8 + 1 + 3 + 1]; /* <8>.<3>'\0' */ 548*0Sstevel@tonic-gate char *p, *ep; 549*0Sstevel@tonic-gate _dir_entry_t dd; 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate dprintf("lookuppn: path = %s\n", n); 552*0Sstevel@tonic-gate dir_blk = pcfsp->f_dclust; 553*0Sstevel@tonic-gate if ((*n == '\\') || (*n == '/')) { 554*0Sstevel@tonic-gate dir_blk = CLUSTER_ROOTDIR; 555*0Sstevel@tonic-gate while ((*n == '\\') || (*n == '/')) 556*0Sstevel@tonic-gate n++; 557*0Sstevel@tonic-gate if (*n == '\0') { 558*0Sstevel@tonic-gate (void) bzero(dp, sizeof (*dp)); 559*0Sstevel@tonic-gate dp->d_cluster = CLUSTER_ROOTDIR; 560*0Sstevel@tonic-gate dp->d_attr = DE_DIRECTORY; 561*0Sstevel@tonic-gate return (0); 562*0Sstevel@tonic-gate } 563*0Sstevel@tonic-gate } 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate ep = &name[0] + sizeof (name); 566*0Sstevel@tonic-gate while (*n) { 567*0Sstevel@tonic-gate (void) bzero(name, sizeof (name)); 568*0Sstevel@tonic-gate p = &name[0]; 569*0Sstevel@tonic-gate while (*n && (*n != '\\') && (*n != '/')) 570*0Sstevel@tonic-gate if (p != ep) 571*0Sstevel@tonic-gate *p++ = *n++; 572*0Sstevel@tonic-gate else { 573*0Sstevel@tonic-gate dprintf("return, name %s is too long\n", name); 574*0Sstevel@tonic-gate return (-1); /* name is too long */ 575*0Sstevel@tonic-gate } 576*0Sstevel@tonic-gate while ((*n == '\\') || (*n == '/')) 577*0Sstevel@tonic-gate n++; 578*0Sstevel@tonic-gate if (lookup(name, &dd, dir_blk) == 0) { 579*0Sstevel@tonic-gate dprintf("return, name %s not found\n", name); 580*0Sstevel@tonic-gate return (-1); 581*0Sstevel@tonic-gate } 582*0Sstevel@tonic-gate dprintf("dd = %x:%x:%x attr = %x\n", 583*0Sstevel@tonic-gate *(int *)&dd, *(((int *)&dd) + 1), 584*0Sstevel@tonic-gate *(((int *)&dd) + 2), dd.d_attr); 585*0Sstevel@tonic-gate if (*n && ((dd.d_attr & DE_DIRECTORY) == 0)) { 586*0Sstevel@tonic-gate dprintf("return, not a directory\n"); 587*0Sstevel@tonic-gate return (-1); 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate dir_blk = dd.d_cluster; 591*0Sstevel@tonic-gate } 592*0Sstevel@tonic-gate (void) bcopy(&dd, dp, sizeof (dd)); 593*0Sstevel@tonic-gate return (0); 594*0Sstevel@tonic-gate } 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate static void * 597*0Sstevel@tonic-gate readblock(int sector, int nsec) 598*0Sstevel@tonic-gate { 599*0Sstevel@tonic-gate if (sector >= nsec_start && sector + nsec <= nsec_start + nsec_cache) 600*0Sstevel@tonic-gate return (cluster_cache + (sector - nsec_start) * SECSIZ); 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate /* read disk sectors */ 603*0Sstevel@tonic-gate head->fi_blocknum = sector; 604*0Sstevel@tonic-gate head->fi_count = nsec * SECSIZ; 605*0Sstevel@tonic-gate head->fi_memp = head->fi_buf; 606*0Sstevel@tonic-gate if (diskread(head)) { 607*0Sstevel@tonic-gate printf("failed to %d sectors at %d\n", nsec, sector); 608*0Sstevel@tonic-gate return (NULL); 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate return (head->fi_buf); 612*0Sstevel@tonic-gate } 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate struct boot_fs_ops bpcfs_ops = { 615*0Sstevel@tonic-gate "boot_pcfs", 616*0Sstevel@tonic-gate bpcfs_mountroot, 617*0Sstevel@tonic-gate bpcfs_unmountroot, 618*0Sstevel@tonic-gate bpcfs_open, 619*0Sstevel@tonic-gate bpcfs_close, 620*0Sstevel@tonic-gate bpcfs_read, 621*0Sstevel@tonic-gate bpcfs_lseek, 622*0Sstevel@tonic-gate NULL 623*0Sstevel@tonic-gate }; 624