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 * Routines to allocate and deallocate data blocks on the disk 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/param.h> 34*0Sstevel@tonic-gate #include <sys/errno.h> 35*0Sstevel@tonic-gate #include <sys/buf.h> 36*0Sstevel@tonic-gate #include <sys/vfs.h> 37*0Sstevel@tonic-gate #include <sys/vnode.h> 38*0Sstevel@tonic-gate #include <sys/cmn_err.h> 39*0Sstevel@tonic-gate #include <sys/debug.h> 40*0Sstevel@tonic-gate #include <sys/sysmacros.h> 41*0Sstevel@tonic-gate #include <sys/systm.h> 42*0Sstevel@tonic-gate #include <sys/fs/pc_label.h> 43*0Sstevel@tonic-gate #include <sys/fs/pc_fs.h> 44*0Sstevel@tonic-gate #include <sys/fs/pc_dir.h> 45*0Sstevel@tonic-gate #include <sys/fs/pc_node.h> 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate static pc_cluster32_t pc_getcluster(struct pcfs *fsp, pc_cluster32_t cn); 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate /* 50*0Sstevel@tonic-gate * Convert file logical block (cluster) numbers to disk block numbers. 51*0Sstevel@tonic-gate * Also return number of physically contiguous blocks if asked for. 52*0Sstevel@tonic-gate * Used for reading only. Use pc_balloc for writing. 53*0Sstevel@tonic-gate */ 54*0Sstevel@tonic-gate int 55*0Sstevel@tonic-gate pc_bmap( 56*0Sstevel@tonic-gate struct pcnode *pcp, /* pcnode for file */ 57*0Sstevel@tonic-gate daddr_t lcn, /* logical cluster no */ 58*0Sstevel@tonic-gate daddr_t *dbnp, /* ptr to phys block no */ 59*0Sstevel@tonic-gate uint_t *contigbp) /* ptr to number of contiguous bytes */ 60*0Sstevel@tonic-gate /* may be zero if not wanted */ 61*0Sstevel@tonic-gate { 62*0Sstevel@tonic-gate struct pcfs *fsp; /* pcfs that file is in */ 63*0Sstevel@tonic-gate struct vnode *vp; 64*0Sstevel@tonic-gate pc_cluster32_t cn, ncn; /* current, next cluster number */ 65*0Sstevel@tonic-gate daddr_t olcn = lcn; 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate PC_DPRINTF2(6, "pc_bmap: pcp=0x%p, lcn=%ld\n", (void *)pcp, lcn); 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate vp = PCTOV(pcp); 70*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 71*0Sstevel@tonic-gate if (lcn < 0) 72*0Sstevel@tonic-gate return (ENOENT); 73*0Sstevel@tonic-gate if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) { 74*0Sstevel@tonic-gate daddr_t lbn, bn; /* logical (disk) block number */ 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate lbn = pc_cltodb(fsp, lcn); 77*0Sstevel@tonic-gate if (lbn >= fsp->pcfs_rdirsec) { 78*0Sstevel@tonic-gate PC_DPRINTF0(2, "pc_bmap: ENOENT1\n"); 79*0Sstevel@tonic-gate return (ENOENT); 80*0Sstevel@tonic-gate } 81*0Sstevel@tonic-gate bn = fsp->pcfs_rdirstart + lbn; 82*0Sstevel@tonic-gate *dbnp = pc_dbdaddr(fsp, bn); 83*0Sstevel@tonic-gate if (contigbp) { 84*0Sstevel@tonic-gate ASSERT (*contigbp >= fsp->pcfs_secsize); 85*0Sstevel@tonic-gate *contigbp = MIN(*contigbp, 86*0Sstevel@tonic-gate fsp->pcfs_secsize * (fsp->pcfs_rdirsec - lbn)); 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate } else { 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate if (lcn >= fsp->pcfs_ncluster) { 91*0Sstevel@tonic-gate PC_DPRINTF0(2, "pc_bmap: ENOENT2\n"); 92*0Sstevel@tonic-gate return (ENOENT); 93*0Sstevel@tonic-gate } 94*0Sstevel@tonic-gate if (vp->v_type == VREG && 95*0Sstevel@tonic-gate (pcp->pc_size == 0 || 96*0Sstevel@tonic-gate lcn >= (daddr_t)howmany((offset_t)pcp->pc_size, 97*0Sstevel@tonic-gate fsp->pcfs_clsize))) { 98*0Sstevel@tonic-gate PC_DPRINTF0(2, "pc_bmap: ENOENT3\n"); 99*0Sstevel@tonic-gate return (ENOENT); 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate ncn = pcp->pc_scluster; 102*0Sstevel@tonic-gate if (IS_FAT32(fsp) && ncn == 0) 103*0Sstevel@tonic-gate ncn = fsp->pcfs_rdirstart; 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate /* Do we have a cached index/cluster pair? */ 106*0Sstevel@tonic-gate if (pcp->pc_lindex > 0 && lcn >= pcp->pc_lindex) { 107*0Sstevel@tonic-gate lcn -= pcp->pc_lindex; 108*0Sstevel@tonic-gate ncn = pcp->pc_lcluster; 109*0Sstevel@tonic-gate } 110*0Sstevel@tonic-gate do { 111*0Sstevel@tonic-gate cn = ncn; 112*0Sstevel@tonic-gate if (!pc_validcl(fsp, cn)) { 113*0Sstevel@tonic-gate if (IS_FAT32(fsp) && cn >= PCF_LASTCLUSTER32 && 114*0Sstevel@tonic-gate vp->v_type == VDIR) { 115*0Sstevel@tonic-gate PC_DPRINTF0(2, "pc_bmap: ENOENT4\n"); 116*0Sstevel@tonic-gate return (ENOENT); 117*0Sstevel@tonic-gate } else if (!IS_FAT32(fsp) && 118*0Sstevel@tonic-gate cn >= PCF_LASTCLUSTER && 119*0Sstevel@tonic-gate vp->v_type == VDIR) { 120*0Sstevel@tonic-gate PC_DPRINTF0(2, "pc_bmap: ENOENT5\n"); 121*0Sstevel@tonic-gate return (ENOENT); 122*0Sstevel@tonic-gate } else { 123*0Sstevel@tonic-gate PC_DPRINTF1(1, 124*0Sstevel@tonic-gate "pc_bmap: badfs cn=%d\n", cn); 125*0Sstevel@tonic-gate (void) pc_badfs(fsp); 126*0Sstevel@tonic-gate return (EIO); 127*0Sstevel@tonic-gate } 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate ncn = pc_getcluster(fsp, cn); 130*0Sstevel@tonic-gate } while (lcn--); 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate /* 133*0Sstevel@tonic-gate * Cache this cluster, as we'll most likely visit the 134*0Sstevel@tonic-gate * one after this next time. Considerably improves 135*0Sstevel@tonic-gate * performance on sequential reads and writes. 136*0Sstevel@tonic-gate */ 137*0Sstevel@tonic-gate pcp->pc_lindex = olcn; 138*0Sstevel@tonic-gate pcp->pc_lcluster = cn; 139*0Sstevel@tonic-gate *dbnp = pc_cldaddr(fsp, cn); 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate if (contigbp && *contigbp > fsp->pcfs_clsize) { 142*0Sstevel@tonic-gate uint_t count = fsp->pcfs_clsize; 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate while ((cn + 1) == ncn && count < *contigbp && 145*0Sstevel@tonic-gate pc_validcl(fsp, ncn)) { 146*0Sstevel@tonic-gate count += fsp->pcfs_clsize; 147*0Sstevel@tonic-gate cn = ncn; 148*0Sstevel@tonic-gate ncn = pc_getcluster(fsp, ncn); 149*0Sstevel@tonic-gate } 150*0Sstevel@tonic-gate *contigbp = count; 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate } 153*0Sstevel@tonic-gate return (0); 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate /* 157*0Sstevel@tonic-gate * Allocate file logical blocks (clusters). 158*0Sstevel@tonic-gate * Return disk address of last allocated cluster. 159*0Sstevel@tonic-gate */ 160*0Sstevel@tonic-gate int 161*0Sstevel@tonic-gate pc_balloc( 162*0Sstevel@tonic-gate struct pcnode *pcp, /* pcnode for file */ 163*0Sstevel@tonic-gate daddr_t lcn, /* logical cluster no */ 164*0Sstevel@tonic-gate int zwrite, /* zerofill blocks? */ 165*0Sstevel@tonic-gate daddr_t *dbnp) /* ptr to phys block no */ 166*0Sstevel@tonic-gate { 167*0Sstevel@tonic-gate struct pcfs *fsp; /* pcfs that file is in */ 168*0Sstevel@tonic-gate struct vnode *vp; 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate PC_DPRINTF2(5, "pc_balloc: pcp=0x%p, lcn=%ld\n", (void *)pcp, lcn); 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate vp = PCTOV(pcp); 173*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp -> v_vfsp); 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate if (lcn < 0) { 176*0Sstevel@tonic-gate return (EFBIG); 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) { 180*0Sstevel@tonic-gate daddr_t lbn; 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate lbn = pc_cltodb(fsp, lcn); 183*0Sstevel@tonic-gate if (lbn >= fsp->pcfs_rdirsec) 184*0Sstevel@tonic-gate return (ENOSPC); 185*0Sstevel@tonic-gate *dbnp = pc_dbdaddr(fsp, fsp->pcfs_rdirstart + lbn); 186*0Sstevel@tonic-gate } else { 187*0Sstevel@tonic-gate pc_cluster32_t cn; /* current cluster number */ 188*0Sstevel@tonic-gate pc_cluster32_t ncn; /* next cluster number */ 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate if (lcn >= fsp->pcfs_ncluster) 191*0Sstevel@tonic-gate return (ENOSPC); 192*0Sstevel@tonic-gate if ((vp->v_type == VREG && pcp->pc_size == 0) || 193*0Sstevel@tonic-gate (vp->v_type == VDIR && lcn == 0)) { 194*0Sstevel@tonic-gate switch (cn = pc_alloccluster(fsp, 1)) { 195*0Sstevel@tonic-gate case PCF_FREECLUSTER: 196*0Sstevel@tonic-gate return (ENOSPC); 197*0Sstevel@tonic-gate case PCF_ERRORCLUSTER: 198*0Sstevel@tonic-gate return (EIO); 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate pcp->pc_scluster = cn; 201*0Sstevel@tonic-gate } else { 202*0Sstevel@tonic-gate cn = pcp->pc_scluster; 203*0Sstevel@tonic-gate if (IS_FAT32(fsp) && cn == 0) 204*0Sstevel@tonic-gate cn = fsp->pcfs_rdirstart; 205*0Sstevel@tonic-gate if (!pc_validcl(fsp, cn)) { 206*0Sstevel@tonic-gate PC_DPRINTF1(1, "pc_balloc: badfs cn=%d\n", cn); 207*0Sstevel@tonic-gate (void) pc_badfs(fsp); 208*0Sstevel@tonic-gate return (EIO); 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate if (pcp->pc_lindex > 0 && lcn > pcp->pc_lindex) { 213*0Sstevel@tonic-gate lcn -= pcp->pc_lindex; 214*0Sstevel@tonic-gate cn = pcp->pc_lcluster; 215*0Sstevel@tonic-gate } 216*0Sstevel@tonic-gate while (lcn-- > 0) { 217*0Sstevel@tonic-gate ncn = pc_getcluster(fsp, cn); 218*0Sstevel@tonic-gate if ((IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER32) || 219*0Sstevel@tonic-gate (!IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER)) { 220*0Sstevel@tonic-gate /* 221*0Sstevel@tonic-gate * Extend file (no holes). 222*0Sstevel@tonic-gate */ 223*0Sstevel@tonic-gate switch (ncn = pc_alloccluster(fsp, zwrite)) { 224*0Sstevel@tonic-gate case PCF_FREECLUSTER: 225*0Sstevel@tonic-gate return (ENOSPC); 226*0Sstevel@tonic-gate case PCF_ERRORCLUSTER: 227*0Sstevel@tonic-gate return (EIO); 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate pc_setcluster(fsp, cn, ncn); 230*0Sstevel@tonic-gate } else if (!pc_validcl(fsp, ncn)) { 231*0Sstevel@tonic-gate PC_DPRINTF1(1, 232*0Sstevel@tonic-gate "pc_balloc: badfs ncn=%d\n", ncn); 233*0Sstevel@tonic-gate (void) pc_badfs(fsp); 234*0Sstevel@tonic-gate return (EIO); 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate cn = ncn; 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate /* 239*0Sstevel@tonic-gate * Do not cache the new cluster/index values; when 240*0Sstevel@tonic-gate * extending the file we're interested in the last 241*0Sstevel@tonic-gate * written cluster and not the last cluster allocated. 242*0Sstevel@tonic-gate */ 243*0Sstevel@tonic-gate *dbnp = pc_cldaddr(fsp, cn); 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate return (0); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate /* 249*0Sstevel@tonic-gate * Free file cluster chain after the first skipcl clusters. 250*0Sstevel@tonic-gate */ 251*0Sstevel@tonic-gate int 252*0Sstevel@tonic-gate pc_bfree(struct pcnode *pcp, pc_cluster32_t skipcl) 253*0Sstevel@tonic-gate { 254*0Sstevel@tonic-gate struct pcfs *fsp; 255*0Sstevel@tonic-gate pc_cluster32_t cn; 256*0Sstevel@tonic-gate pc_cluster32_t ncn; 257*0Sstevel@tonic-gate int n; 258*0Sstevel@tonic-gate struct vnode *vp; 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate vp = PCTOV(pcp); 261*0Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp); 262*0Sstevel@tonic-gate if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) { 263*0Sstevel@tonic-gate panic("pc_bfree"); 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate PC_DPRINTF2(5, "pc_bfree: pcp=0x%p, after first %d clusters\n", 267*0Sstevel@tonic-gate (void *)pcp, skipcl); 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate if (pcp->pc_size == 0 && vp->v_type == VREG) { 270*0Sstevel@tonic-gate return (0); 271*0Sstevel@tonic-gate } 272*0Sstevel@tonic-gate if (vp->v_type == VREG) { 273*0Sstevel@tonic-gate n = (int)howmany((offset_t)pcp->pc_size, fsp->pcfs_clsize); 274*0Sstevel@tonic-gate if (n > fsp->pcfs_ncluster) { 275*0Sstevel@tonic-gate PC_DPRINTF1(1, "pc_bfree: badfs n=%d\n", n); 276*0Sstevel@tonic-gate (void) pc_badfs(fsp); 277*0Sstevel@tonic-gate return (EIO); 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate } else { 280*0Sstevel@tonic-gate n = fsp->pcfs_ncluster; 281*0Sstevel@tonic-gate } 282*0Sstevel@tonic-gate cn = pcp->pc_scluster; 283*0Sstevel@tonic-gate if (IS_FAT32(fsp) && cn == 0) 284*0Sstevel@tonic-gate cn = fsp->pcfs_rdirstart; 285*0Sstevel@tonic-gate if (skipcl == 0) { 286*0Sstevel@tonic-gate if (IS_FAT32(fsp)) 287*0Sstevel@tonic-gate pcp->pc_scluster = PCF_LASTCLUSTERMARK32; 288*0Sstevel@tonic-gate else 289*0Sstevel@tonic-gate pcp->pc_scluster = PCF_LASTCLUSTERMARK; 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate /* Invalidate last used cluster cache */ 293*0Sstevel@tonic-gate pcp->pc_lindex = 0; 294*0Sstevel@tonic-gate pcp->pc_lcluster = pcp->pc_scluster; 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate while (n--) { 297*0Sstevel@tonic-gate if (!pc_validcl(fsp, cn)) { 298*0Sstevel@tonic-gate PC_DPRINTF1(1, "pc_bfree: badfs cn=%d\n", cn); 299*0Sstevel@tonic-gate (void) pc_badfs(fsp); 300*0Sstevel@tonic-gate return (EIO); 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate ncn = pc_getcluster(fsp, cn); 303*0Sstevel@tonic-gate if (skipcl == 0) { 304*0Sstevel@tonic-gate pc_setcluster(fsp, cn, PCF_FREECLUSTER); 305*0Sstevel@tonic-gate } else { 306*0Sstevel@tonic-gate skipcl--; 307*0Sstevel@tonic-gate if (skipcl == 0) { 308*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { 309*0Sstevel@tonic-gate pc_setcluster(fsp, cn, 310*0Sstevel@tonic-gate PCF_LASTCLUSTERMARK32); 311*0Sstevel@tonic-gate } else 312*0Sstevel@tonic-gate pc_setcluster(fsp, cn, 313*0Sstevel@tonic-gate PCF_LASTCLUSTERMARK); 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate if (IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER32 && 317*0Sstevel@tonic-gate vp->v_type == VDIR) 318*0Sstevel@tonic-gate break; 319*0Sstevel@tonic-gate if (!IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER && 320*0Sstevel@tonic-gate vp->v_type == VDIR) 321*0Sstevel@tonic-gate break; 322*0Sstevel@tonic-gate cn = ncn; 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate return (0); 325*0Sstevel@tonic-gate } 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate /* 328*0Sstevel@tonic-gate * Return the number of free blocks in the filesystem. 329*0Sstevel@tonic-gate */ 330*0Sstevel@tonic-gate int 331*0Sstevel@tonic-gate pc_freeclusters(struct pcfs *fsp) 332*0Sstevel@tonic-gate { 333*0Sstevel@tonic-gate pc_cluster32_t cn; 334*0Sstevel@tonic-gate int free; 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate /* 337*0Sstevel@tonic-gate * make sure the FAT is in core 338*0Sstevel@tonic-gate */ 339*0Sstevel@tonic-gate free = 0; 340*0Sstevel@tonic-gate for (cn = PCF_FIRSTCLUSTER; 341*0Sstevel@tonic-gate (int)cn <= fsp->pcfs_ncluster; cn++) { 342*0Sstevel@tonic-gate if (pc_getcluster(fsp, cn) == PCF_FREECLUSTER) { 343*0Sstevel@tonic-gate free++; 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate return (free); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate /* 350*0Sstevel@tonic-gate * Cluster manipulation routines. 351*0Sstevel@tonic-gate * FAT must be resident. 352*0Sstevel@tonic-gate */ 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate /* 355*0Sstevel@tonic-gate * Get the next cluster in the file cluster chain. 356*0Sstevel@tonic-gate * cn = current cluster number in chain 357*0Sstevel@tonic-gate */ 358*0Sstevel@tonic-gate static pc_cluster32_t 359*0Sstevel@tonic-gate pc_getcluster(struct pcfs *fsp, pc_cluster32_t cn) 360*0Sstevel@tonic-gate { 361*0Sstevel@tonic-gate unsigned char *fp; 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate PC_DPRINTF1(7, "pc_getcluster: cn=%x ", cn); 364*0Sstevel@tonic-gate if (fsp->pcfs_fatp == (uchar_t *)0 || !pc_validcl(fsp, cn)) 365*0Sstevel@tonic-gate panic("pc_getcluster"); 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { /* 32 bit FAT */ 368*0Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn << 2); 369*0Sstevel@tonic-gate cn = ltohi(*(pc_cluster32_t *)fp); 370*0Sstevel@tonic-gate } else if (fsp->pcfs_flags & PCFS_FAT16) { /* 16 bit FAT */ 371*0Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn << 1); 372*0Sstevel@tonic-gate cn = ltohs(*(pc_cluster16_t *)fp); 373*0Sstevel@tonic-gate } else { /* 12 bit FAT */ 374*0Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn + (cn >> 1)); 375*0Sstevel@tonic-gate if (cn & 01) { 376*0Sstevel@tonic-gate cn = (((unsigned int)*fp++ & 0xf0) >> 4); 377*0Sstevel@tonic-gate cn += (*fp << 4); 378*0Sstevel@tonic-gate } else { 379*0Sstevel@tonic-gate cn = *fp++; 380*0Sstevel@tonic-gate cn += ((*fp & 0x0f) << 8); 381*0Sstevel@tonic-gate } 382*0Sstevel@tonic-gate if (cn >= PCF_12BCLUSTER) 383*0Sstevel@tonic-gate cn |= PCF_RESCLUSTER; 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate PC_DPRINTF1(7, " %x\n", cn); 386*0Sstevel@tonic-gate return (cn); 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate /* 390*0Sstevel@tonic-gate * Set a cluster in the FAT to a value. 391*0Sstevel@tonic-gate * cn = cluster number to be set in FAT 392*0Sstevel@tonic-gate * ncn = new value 393*0Sstevel@tonic-gate */ 394*0Sstevel@tonic-gate void 395*0Sstevel@tonic-gate pc_setcluster(struct pcfs *fsp, pc_cluster32_t cn, pc_cluster32_t ncn) 396*0Sstevel@tonic-gate { 397*0Sstevel@tonic-gate unsigned char *fp; 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate PC_DPRINTF2(7, "pc_setcluster: cn=%d ncn=%d\n", cn, ncn); 400*0Sstevel@tonic-gate if (fsp->pcfs_fatp == (uchar_t *)0 || !pc_validcl(fsp, cn)) 401*0Sstevel@tonic-gate panic("pc_setcluster"); 402*0Sstevel@tonic-gate fsp->pcfs_flags |= PCFS_FATMOD; 403*0Sstevel@tonic-gate pc_mark_fat_updated(fsp, cn); 404*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { /* 32 bit FAT */ 405*0Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn << 2); 406*0Sstevel@tonic-gate *(pc_cluster32_t *)fp = htoli(ncn); 407*0Sstevel@tonic-gate } else if (fsp->pcfs_flags & PCFS_FAT16) { /* 16 bit FAT */ 408*0Sstevel@tonic-gate pc_cluster16_t ncn16; 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn << 1); 411*0Sstevel@tonic-gate ncn16 = (pc_cluster16_t)ncn; 412*0Sstevel@tonic-gate *(pc_cluster16_t *)fp = htols(ncn16); 413*0Sstevel@tonic-gate } else { /* 12 bit FAT */ 414*0Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn + (cn >> 1)); 415*0Sstevel@tonic-gate if (cn & 01) { 416*0Sstevel@tonic-gate *fp = (*fp & 0x0f) | ((ncn << 4) & 0xf0); 417*0Sstevel@tonic-gate fp++; 418*0Sstevel@tonic-gate *fp = (ncn >> 4) & 0xff; 419*0Sstevel@tonic-gate } else { 420*0Sstevel@tonic-gate *fp++ = ncn & 0xff; 421*0Sstevel@tonic-gate *fp = (*fp & 0xf0) | ((ncn >> 8) & 0x0f); 422*0Sstevel@tonic-gate } 423*0Sstevel@tonic-gate } 424*0Sstevel@tonic-gate if (ncn == PCF_FREECLUSTER) { 425*0Sstevel@tonic-gate fsp->pcfs_nxfrecls = PCF_FIRSTCLUSTER; 426*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { 427*0Sstevel@tonic-gate if (fsp->fsinfo_native.fs_free_clusters != 428*0Sstevel@tonic-gate FSINFO_UNKNOWN) 429*0Sstevel@tonic-gate fsp->fsinfo_native.fs_free_clusters++; 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate } 432*0Sstevel@tonic-gate } 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate /* 435*0Sstevel@tonic-gate * Allocate a new cluster. 436*0Sstevel@tonic-gate */ 437*0Sstevel@tonic-gate pc_cluster32_t 438*0Sstevel@tonic-gate pc_alloccluster( 439*0Sstevel@tonic-gate struct pcfs *fsp, /* file sys to allocate in */ 440*0Sstevel@tonic-gate int zwrite) /* boolean for writing zeroes */ 441*0Sstevel@tonic-gate { 442*0Sstevel@tonic-gate pc_cluster32_t cn; 443*0Sstevel@tonic-gate int error; 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate if (fsp->pcfs_fatp == (uchar_t *)0) 446*0Sstevel@tonic-gate panic("pc_addcluster: no FAT"); 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate for (cn = fsp->pcfs_nxfrecls; 449*0Sstevel@tonic-gate (int)cn <= fsp->pcfs_ncluster; cn++) { 450*0Sstevel@tonic-gate if (pc_getcluster(fsp, cn) == PCF_FREECLUSTER) { 451*0Sstevel@tonic-gate struct buf *bp; 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate if (IS_FAT32(fsp)) { 454*0Sstevel@tonic-gate pc_setcluster(fsp, cn, PCF_LASTCLUSTERMARK32); 455*0Sstevel@tonic-gate if (fsp->fsinfo_native.fs_free_clusters != 456*0Sstevel@tonic-gate FSINFO_UNKNOWN) 457*0Sstevel@tonic-gate fsp->fsinfo_native.fs_free_clusters--; 458*0Sstevel@tonic-gate } else 459*0Sstevel@tonic-gate pc_setcluster(fsp, cn, PCF_LASTCLUSTERMARK); 460*0Sstevel@tonic-gate if (zwrite) { 461*0Sstevel@tonic-gate /* 462*0Sstevel@tonic-gate * zero the new cluster 463*0Sstevel@tonic-gate */ 464*0Sstevel@tonic-gate bp = ngeteblk(fsp->pcfs_clsize); 465*0Sstevel@tonic-gate bp->b_edev = fsp->pcfs_xdev; 466*0Sstevel@tonic-gate bp->b_dev = cmpdev(bp->b_edev); 467*0Sstevel@tonic-gate bp->b_blkno = pc_cldaddr(fsp, cn); 468*0Sstevel@tonic-gate clrbuf(bp); 469*0Sstevel@tonic-gate bwrite2(bp); 470*0Sstevel@tonic-gate error = geterror(bp); 471*0Sstevel@tonic-gate brelse(bp); 472*0Sstevel@tonic-gate if (error) { 473*0Sstevel@tonic-gate PC_DPRINTF0(1, 474*0Sstevel@tonic-gate "pc_alloccluster: error\n"); 475*0Sstevel@tonic-gate pc_mark_irrecov(fsp); 476*0Sstevel@tonic-gate return (PCF_ERRORCLUSTER); 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate fsp->pcfs_nxfrecls = cn + 1; 480*0Sstevel@tonic-gate PC_DPRINTF1(5, "pc_alloccluster: new cluster = %d\n", 481*0Sstevel@tonic-gate cn); 482*0Sstevel@tonic-gate return (cn); 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate return (PCF_FREECLUSTER); 486*0Sstevel@tonic-gate } 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate /* 489*0Sstevel@tonic-gate * Get the number of clusters used by a file or subdirectory 490*0Sstevel@tonic-gate */ 491*0Sstevel@tonic-gate int 492*0Sstevel@tonic-gate pc_fileclsize( 493*0Sstevel@tonic-gate struct pcfs *fsp, 494*0Sstevel@tonic-gate pc_cluster32_t strtcluster) 495*0Sstevel@tonic-gate { 496*0Sstevel@tonic-gate int count = 0; 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate while (pc_validcl(fsp, strtcluster)) { 499*0Sstevel@tonic-gate count++; 500*0Sstevel@tonic-gate strtcluster = pc_getcluster(fsp, strtcluster); 501*0Sstevel@tonic-gate } 502*0Sstevel@tonic-gate return (count); 503*0Sstevel@tonic-gate } 504