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
52720Sfrankho * Common Development and Distribution License (the "License").
62720Sfrankho * 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*9251SMichael.Bergknoff@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * Routines to allocate and deallocate data blocks on the disk
280Sstevel@tonic-gate */
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <sys/param.h>
310Sstevel@tonic-gate #include <sys/errno.h>
320Sstevel@tonic-gate #include <sys/buf.h>
330Sstevel@tonic-gate #include <sys/vfs.h>
340Sstevel@tonic-gate #include <sys/vnode.h>
350Sstevel@tonic-gate #include <sys/cmn_err.h>
360Sstevel@tonic-gate #include <sys/debug.h>
370Sstevel@tonic-gate #include <sys/sysmacros.h>
380Sstevel@tonic-gate #include <sys/systm.h>
390Sstevel@tonic-gate #include <sys/fs/pc_label.h>
400Sstevel@tonic-gate #include <sys/fs/pc_fs.h>
410Sstevel@tonic-gate #include <sys/fs/pc_dir.h>
420Sstevel@tonic-gate #include <sys/fs/pc_node.h>
430Sstevel@tonic-gate
440Sstevel@tonic-gate static pc_cluster32_t pc_getcluster(struct pcfs *fsp, pc_cluster32_t cn);
450Sstevel@tonic-gate
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate * Convert file logical block (cluster) numbers to disk block numbers.
480Sstevel@tonic-gate * Also return number of physically contiguous blocks if asked for.
490Sstevel@tonic-gate * Used for reading only. Use pc_balloc for writing.
500Sstevel@tonic-gate */
510Sstevel@tonic-gate int
pc_bmap(struct pcnode * pcp,daddr_t lcn,daddr_t * dbnp,uint_t * contigbp)520Sstevel@tonic-gate pc_bmap(
530Sstevel@tonic-gate struct pcnode *pcp, /* pcnode for file */
540Sstevel@tonic-gate daddr_t lcn, /* logical cluster no */
550Sstevel@tonic-gate daddr_t *dbnp, /* ptr to phys block no */
560Sstevel@tonic-gate uint_t *contigbp) /* ptr to number of contiguous bytes */
570Sstevel@tonic-gate /* may be zero if not wanted */
580Sstevel@tonic-gate {
590Sstevel@tonic-gate struct pcfs *fsp; /* pcfs that file is in */
600Sstevel@tonic-gate struct vnode *vp;
610Sstevel@tonic-gate pc_cluster32_t cn, ncn; /* current, next cluster number */
620Sstevel@tonic-gate daddr_t olcn = lcn;
630Sstevel@tonic-gate
640Sstevel@tonic-gate vp = PCTOV(pcp);
650Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
665121Sfrankho
670Sstevel@tonic-gate if (lcn < 0)
680Sstevel@tonic-gate return (ENOENT);
695121Sfrankho
705121Sfrankho /*
715121Sfrankho * FAT12 / FAT16 root directories are a continuous section on disk
725121Sfrankho * before the actual data clusters. Specialcase this here.
735121Sfrankho */
740Sstevel@tonic-gate if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) {
755121Sfrankho daddr_t lbn; /* logical (disk) block number */
760Sstevel@tonic-gate
770Sstevel@tonic-gate lbn = pc_cltodb(fsp, lcn);
780Sstevel@tonic-gate if (lbn >= fsp->pcfs_rdirsec) {
790Sstevel@tonic-gate PC_DPRINTF0(2, "pc_bmap: ENOENT1\n");
800Sstevel@tonic-gate return (ENOENT);
810Sstevel@tonic-gate }
825121Sfrankho *dbnp = pc_dbdaddr(fsp, fsp->pcfs_rdirstart + lbn);
830Sstevel@tonic-gate if (contigbp) {
840Sstevel@tonic-gate ASSERT (*contigbp >= fsp->pcfs_secsize);
850Sstevel@tonic-gate *contigbp = MIN(*contigbp,
860Sstevel@tonic-gate fsp->pcfs_secsize * (fsp->pcfs_rdirsec - lbn));
870Sstevel@tonic-gate }
885121Sfrankho return (0);
895121Sfrankho }
905121Sfrankho
915121Sfrankho if (lcn >= fsp->pcfs_ncluster) {
925121Sfrankho PC_DPRINTF0(2, "pc_bmap: ENOENT2\n");
935121Sfrankho return (ENOENT);
945121Sfrankho }
955121Sfrankho if (vp->v_type == VREG &&
965121Sfrankho (pcp->pc_size == 0 ||
975121Sfrankho lcn >= (daddr_t)howmany((offset_t)pcp->pc_size,
985121Sfrankho fsp->pcfs_clsize))) {
995121Sfrankho PC_DPRINTF0(2, "pc_bmap: ENOENT3\n");
1005121Sfrankho return (ENOENT);
1015121Sfrankho }
1025121Sfrankho ncn = pcp->pc_scluster;
1035121Sfrankho if (IS_FAT32(fsp) && ncn == 0)
1045121Sfrankho ncn = fsp->pcfs_rdirstart;
1050Sstevel@tonic-gate
1065121Sfrankho /* Do we have a cached index/cluster pair? */
1075121Sfrankho if (pcp->pc_lindex > 0 && lcn >= pcp->pc_lindex) {
1085121Sfrankho lcn -= pcp->pc_lindex;
1095121Sfrankho ncn = pcp->pc_lcluster;
1105121Sfrankho }
1115121Sfrankho do {
1125121Sfrankho cn = ncn;
1135121Sfrankho if (!pc_validcl(fsp, cn)) {
1145121Sfrankho if (IS_FAT32(fsp) && cn >= PCF_LASTCLUSTER32 &&
1155121Sfrankho vp->v_type == VDIR) {
1165121Sfrankho PC_DPRINTF0(2, "pc_bmap: ENOENT4\n");
1175121Sfrankho return (ENOENT);
1185121Sfrankho } else if (!IS_FAT32(fsp) &&
1195121Sfrankho cn >= PCF_LASTCLUSTER &&
1205121Sfrankho vp->v_type == VDIR) {
1215121Sfrankho PC_DPRINTF0(2, "pc_bmap: ENOENT5\n");
1225121Sfrankho return (ENOENT);
1235121Sfrankho } else {
1245121Sfrankho PC_DPRINTF1(1,
1255121Sfrankho "pc_bmap: badfs cn=%d\n", cn);
1265121Sfrankho (void) pc_badfs(fsp);
1275121Sfrankho return (EIO);
1285121Sfrankho }
1290Sstevel@tonic-gate }
1305121Sfrankho ncn = pc_getcluster(fsp, cn);
1315121Sfrankho } while (lcn--);
1320Sstevel@tonic-gate
1335121Sfrankho /*
1345121Sfrankho * Cache this cluster, as we'll most likely visit the
1355121Sfrankho * one after this next time. Considerably improves
1365121Sfrankho * performance on sequential reads and writes.
1375121Sfrankho */
1385121Sfrankho pcp->pc_lindex = olcn;
1395121Sfrankho pcp->pc_lcluster = cn;
1405121Sfrankho *dbnp = pc_cldaddr(fsp, cn);
1415121Sfrankho
1425121Sfrankho if (contigbp && *contigbp > fsp->pcfs_clsize) {
1435121Sfrankho uint_t count = fsp->pcfs_clsize;
1445121Sfrankho
1455121Sfrankho while ((cn + 1) == ncn && count < *contigbp &&
1465121Sfrankho pc_validcl(fsp, ncn)) {
1475121Sfrankho count += fsp->pcfs_clsize;
1480Sstevel@tonic-gate cn = ncn;
1495121Sfrankho ncn = pc_getcluster(fsp, ncn);
1500Sstevel@tonic-gate }
1515121Sfrankho *contigbp = count;
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate return (0);
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate * Allocate file logical blocks (clusters).
1580Sstevel@tonic-gate * Return disk address of last allocated cluster.
1590Sstevel@tonic-gate */
1600Sstevel@tonic-gate int
pc_balloc(struct pcnode * pcp,daddr_t lcn,int zwrite,daddr_t * dbnp)1610Sstevel@tonic-gate pc_balloc(
1620Sstevel@tonic-gate struct pcnode *pcp, /* pcnode for file */
1630Sstevel@tonic-gate daddr_t lcn, /* logical cluster no */
1640Sstevel@tonic-gate int zwrite, /* zerofill blocks? */
1650Sstevel@tonic-gate daddr_t *dbnp) /* ptr to phys block no */
1660Sstevel@tonic-gate {
1670Sstevel@tonic-gate struct pcfs *fsp; /* pcfs that file is in */
1680Sstevel@tonic-gate struct vnode *vp;
1695121Sfrankho pc_cluster32_t cn; /* current cluster number */
1705121Sfrankho pc_cluster32_t ncn; /* next cluster number */
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate vp = PCTOV(pcp);
1730Sstevel@tonic-gate fsp = VFSTOPCFS(vp -> v_vfsp);
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate if (lcn < 0) {
1760Sstevel@tonic-gate return (EFBIG);
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate
1795121Sfrankho /*
1805121Sfrankho * Again, FAT12/FAT16 root directories are not data clusters.
1815121Sfrankho */
1820Sstevel@tonic-gate if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) {
1830Sstevel@tonic-gate daddr_t lbn;
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate lbn = pc_cltodb(fsp, lcn);
1860Sstevel@tonic-gate if (lbn >= fsp->pcfs_rdirsec)
1870Sstevel@tonic-gate return (ENOSPC);
1880Sstevel@tonic-gate *dbnp = pc_dbdaddr(fsp, fsp->pcfs_rdirstart + lbn);
1895121Sfrankho return (0);
1905121Sfrankho }
1910Sstevel@tonic-gate
1925121Sfrankho if (lcn >= fsp->pcfs_ncluster)
1935121Sfrankho return (ENOSPC);
1945121Sfrankho if ((vp->v_type == VREG && pcp->pc_size == 0) ||
1955121Sfrankho (vp->v_type == VDIR && lcn == 0)) {
1965121Sfrankho switch (cn = pc_alloccluster(fsp, 1)) {
1975121Sfrankho case PCF_FREECLUSTER:
1980Sstevel@tonic-gate return (ENOSPC);
1995121Sfrankho case PCF_ERRORCLUSTER:
2005121Sfrankho return (EIO);
2015121Sfrankho }
2025121Sfrankho pcp->pc_scluster = cn;
2035121Sfrankho } else {
2045121Sfrankho cn = pcp->pc_scluster;
2055121Sfrankho if (IS_FAT32(fsp) && cn == 0)
2065121Sfrankho cn = fsp->pcfs_rdirstart;
2075121Sfrankho if (!pc_validcl(fsp, cn)) {
2085121Sfrankho PC_DPRINTF1(1, "pc_balloc: badfs cn=%d\n", cn);
2095121Sfrankho (void) pc_badfs(fsp);
2105121Sfrankho return (EIO);
2115121Sfrankho }
2125121Sfrankho }
2135121Sfrankho
2145121Sfrankho if (pcp->pc_lindex > 0 && lcn > pcp->pc_lindex) {
2155121Sfrankho lcn -= pcp->pc_lindex;
2165121Sfrankho cn = pcp->pc_lcluster;
2175121Sfrankho }
2185121Sfrankho while (lcn-- > 0) {
2195121Sfrankho ncn = pc_getcluster(fsp, cn);
2205121Sfrankho if ((IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER32) ||
2215121Sfrankho (!IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER)) {
2225121Sfrankho /*
2235121Sfrankho * Extend file (no holes).
2245121Sfrankho */
2255121Sfrankho switch (ncn = pc_alloccluster(fsp, zwrite)) {
2260Sstevel@tonic-gate case PCF_FREECLUSTER:
2270Sstevel@tonic-gate return (ENOSPC);
2280Sstevel@tonic-gate case PCF_ERRORCLUSTER:
2290Sstevel@tonic-gate return (EIO);
2300Sstevel@tonic-gate }
2315121Sfrankho pc_setcluster(fsp, cn, ncn);
2325121Sfrankho } else if (!pc_validcl(fsp, ncn)) {
2335121Sfrankho PC_DPRINTF1(1,
2345121Sfrankho "pc_balloc: badfs ncn=%d\n", ncn);
2355121Sfrankho (void) pc_badfs(fsp);
2365121Sfrankho return (EIO);
2370Sstevel@tonic-gate }
2385121Sfrankho cn = ncn;
2390Sstevel@tonic-gate }
2405121Sfrankho /*
2415121Sfrankho * Do not cache the new cluster/index values; when
2425121Sfrankho * extending the file we're interested in the last
2435121Sfrankho * written cluster and not the last cluster allocated.
2445121Sfrankho */
2455121Sfrankho *dbnp = pc_cldaddr(fsp, cn);
2465121Sfrankho
2470Sstevel@tonic-gate return (0);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate * Free file cluster chain after the first skipcl clusters.
2520Sstevel@tonic-gate */
2530Sstevel@tonic-gate int
pc_bfree(struct pcnode * pcp,pc_cluster32_t skipcl)2540Sstevel@tonic-gate pc_bfree(struct pcnode *pcp, pc_cluster32_t skipcl)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate struct pcfs *fsp;
2570Sstevel@tonic-gate pc_cluster32_t cn;
2580Sstevel@tonic-gate pc_cluster32_t ncn;
2590Sstevel@tonic-gate int n;
2600Sstevel@tonic-gate struct vnode *vp;
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate vp = PCTOV(pcp);
2630Sstevel@tonic-gate fsp = VFSTOPCFS(vp->v_vfsp);
2640Sstevel@tonic-gate if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) {
2650Sstevel@tonic-gate panic("pc_bfree");
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate if (pcp->pc_size == 0 && vp->v_type == VREG) {
2690Sstevel@tonic-gate return (0);
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate if (vp->v_type == VREG) {
2720Sstevel@tonic-gate n = (int)howmany((offset_t)pcp->pc_size, fsp->pcfs_clsize);
2730Sstevel@tonic-gate if (n > fsp->pcfs_ncluster) {
2740Sstevel@tonic-gate PC_DPRINTF1(1, "pc_bfree: badfs n=%d\n", n);
2750Sstevel@tonic-gate (void) pc_badfs(fsp);
2760Sstevel@tonic-gate return (EIO);
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate } else {
2790Sstevel@tonic-gate n = fsp->pcfs_ncluster;
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate cn = pcp->pc_scluster;
2820Sstevel@tonic-gate if (IS_FAT32(fsp) && cn == 0)
2830Sstevel@tonic-gate cn = fsp->pcfs_rdirstart;
2840Sstevel@tonic-gate if (skipcl == 0) {
2850Sstevel@tonic-gate if (IS_FAT32(fsp))
2860Sstevel@tonic-gate pcp->pc_scluster = PCF_LASTCLUSTERMARK32;
2870Sstevel@tonic-gate else
2880Sstevel@tonic-gate pcp->pc_scluster = PCF_LASTCLUSTERMARK;
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate /* Invalidate last used cluster cache */
2920Sstevel@tonic-gate pcp->pc_lindex = 0;
2930Sstevel@tonic-gate pcp->pc_lcluster = pcp->pc_scluster;
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate while (n--) {
2960Sstevel@tonic-gate if (!pc_validcl(fsp, cn)) {
2970Sstevel@tonic-gate PC_DPRINTF1(1, "pc_bfree: badfs cn=%d\n", cn);
2980Sstevel@tonic-gate (void) pc_badfs(fsp);
2990Sstevel@tonic-gate return (EIO);
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate ncn = pc_getcluster(fsp, cn);
3020Sstevel@tonic-gate if (skipcl == 0) {
3030Sstevel@tonic-gate pc_setcluster(fsp, cn, PCF_FREECLUSTER);
3040Sstevel@tonic-gate } else {
3050Sstevel@tonic-gate skipcl--;
3060Sstevel@tonic-gate if (skipcl == 0) {
3070Sstevel@tonic-gate if (IS_FAT32(fsp)) {
3080Sstevel@tonic-gate pc_setcluster(fsp, cn,
3090Sstevel@tonic-gate PCF_LASTCLUSTERMARK32);
3100Sstevel@tonic-gate } else
3110Sstevel@tonic-gate pc_setcluster(fsp, cn,
3120Sstevel@tonic-gate PCF_LASTCLUSTERMARK);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate if (IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER32 &&
3160Sstevel@tonic-gate vp->v_type == VDIR)
3170Sstevel@tonic-gate break;
3180Sstevel@tonic-gate if (!IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER &&
3190Sstevel@tonic-gate vp->v_type == VDIR)
3200Sstevel@tonic-gate break;
3210Sstevel@tonic-gate cn = ncn;
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate return (0);
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate /*
3270Sstevel@tonic-gate * Return the number of free blocks in the filesystem.
3280Sstevel@tonic-gate */
3290Sstevel@tonic-gate int
pc_freeclusters(struct pcfs * fsp)3300Sstevel@tonic-gate pc_freeclusters(struct pcfs *fsp)
3310Sstevel@tonic-gate {
3320Sstevel@tonic-gate pc_cluster32_t cn;
3332720Sfrankho int free = 0;
3342720Sfrankho
3352720Sfrankho if (IS_FAT32(fsp) &&
3365121Sfrankho fsp->pcfs_fsinfo.fs_free_clusters != FSINFO_UNKNOWN)
3375121Sfrankho return (fsp->pcfs_fsinfo.fs_free_clusters);
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate /*
3400Sstevel@tonic-gate * make sure the FAT is in core
3410Sstevel@tonic-gate */
342*9251SMichael.Bergknoff@Sun.COM for (cn = PCF_FIRSTCLUSTER; pc_validcl(fsp, cn); cn++) {
3430Sstevel@tonic-gate if (pc_getcluster(fsp, cn) == PCF_FREECLUSTER) {
3440Sstevel@tonic-gate free++;
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate }
3472720Sfrankho
3482720Sfrankho if (IS_FAT32(fsp)) {
3495121Sfrankho ASSERT(fsp->pcfs_fsinfo.fs_free_clusters == FSINFO_UNKNOWN);
3505121Sfrankho fsp->pcfs_fsinfo.fs_free_clusters = free;
3512720Sfrankho }
3520Sstevel@tonic-gate return (free);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate /*
3560Sstevel@tonic-gate * Cluster manipulation routines.
3570Sstevel@tonic-gate * FAT must be resident.
3580Sstevel@tonic-gate */
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate * Get the next cluster in the file cluster chain.
3620Sstevel@tonic-gate * cn = current cluster number in chain
3630Sstevel@tonic-gate */
3640Sstevel@tonic-gate static pc_cluster32_t
pc_getcluster(struct pcfs * fsp,pc_cluster32_t cn)3650Sstevel@tonic-gate pc_getcluster(struct pcfs *fsp, pc_cluster32_t cn)
3660Sstevel@tonic-gate {
3670Sstevel@tonic-gate unsigned char *fp;
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate if (fsp->pcfs_fatp == (uchar_t *)0 || !pc_validcl(fsp, cn))
3700Sstevel@tonic-gate panic("pc_getcluster");
3710Sstevel@tonic-gate
3725121Sfrankho switch (fsp->pcfs_fattype) {
3735121Sfrankho case FAT32:
3740Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn << 2);
3750Sstevel@tonic-gate cn = ltohi(*(pc_cluster32_t *)fp);
3765121Sfrankho break;
3775121Sfrankho case FAT16:
3780Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn << 1);
3790Sstevel@tonic-gate cn = ltohs(*(pc_cluster16_t *)fp);
3805121Sfrankho break;
3815121Sfrankho case FAT12:
3820Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn + (cn >> 1));
3830Sstevel@tonic-gate if (cn & 01) {
3840Sstevel@tonic-gate cn = (((unsigned int)*fp++ & 0xf0) >> 4);
3850Sstevel@tonic-gate cn += (*fp << 4);
3860Sstevel@tonic-gate } else {
3870Sstevel@tonic-gate cn = *fp++;
3880Sstevel@tonic-gate cn += ((*fp & 0x0f) << 8);
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate if (cn >= PCF_12BCLUSTER)
3910Sstevel@tonic-gate cn |= PCF_RESCLUSTER;
3925121Sfrankho break;
3935121Sfrankho default:
3945121Sfrankho pc_mark_irrecov(fsp);
3955121Sfrankho cn = PCF_ERRORCLUSTER;
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate return (cn);
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate /*
4010Sstevel@tonic-gate * Set a cluster in the FAT to a value.
4020Sstevel@tonic-gate * cn = cluster number to be set in FAT
4030Sstevel@tonic-gate * ncn = new value
4040Sstevel@tonic-gate */
4050Sstevel@tonic-gate void
pc_setcluster(struct pcfs * fsp,pc_cluster32_t cn,pc_cluster32_t ncn)4060Sstevel@tonic-gate pc_setcluster(struct pcfs *fsp, pc_cluster32_t cn, pc_cluster32_t ncn)
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate unsigned char *fp;
4095121Sfrankho pc_cluster16_t ncn16;
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate if (fsp->pcfs_fatp == (uchar_t *)0 || !pc_validcl(fsp, cn))
4120Sstevel@tonic-gate panic("pc_setcluster");
4130Sstevel@tonic-gate fsp->pcfs_flags |= PCFS_FATMOD;
4140Sstevel@tonic-gate pc_mark_fat_updated(fsp, cn);
4155121Sfrankho switch (fsp->pcfs_fattype) {
4165121Sfrankho case FAT32:
4170Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn << 2);
4180Sstevel@tonic-gate *(pc_cluster32_t *)fp = htoli(ncn);
4195121Sfrankho break;
4205121Sfrankho case FAT16:
4210Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn << 1);
4220Sstevel@tonic-gate ncn16 = (pc_cluster16_t)ncn;
4230Sstevel@tonic-gate *(pc_cluster16_t *)fp = htols(ncn16);
4245121Sfrankho break;
4255121Sfrankho case FAT12:
4260Sstevel@tonic-gate fp = fsp->pcfs_fatp + (cn + (cn >> 1));
4270Sstevel@tonic-gate if (cn & 01) {
4280Sstevel@tonic-gate *fp = (*fp & 0x0f) | ((ncn << 4) & 0xf0);
4290Sstevel@tonic-gate fp++;
4300Sstevel@tonic-gate *fp = (ncn >> 4) & 0xff;
4310Sstevel@tonic-gate } else {
4320Sstevel@tonic-gate *fp++ = ncn & 0xff;
4330Sstevel@tonic-gate *fp = (*fp & 0xf0) | ((ncn >> 8) & 0x0f);
4340Sstevel@tonic-gate }
4355121Sfrankho break;
4365121Sfrankho default:
4375121Sfrankho pc_mark_irrecov(fsp);
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate if (ncn == PCF_FREECLUSTER) {
4400Sstevel@tonic-gate fsp->pcfs_nxfrecls = PCF_FIRSTCLUSTER;
4410Sstevel@tonic-gate if (IS_FAT32(fsp)) {
4425121Sfrankho if (fsp->pcfs_fsinfo.fs_free_clusters !=
4430Sstevel@tonic-gate FSINFO_UNKNOWN)
4445121Sfrankho fsp->pcfs_fsinfo.fs_free_clusters++;
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate /*
4500Sstevel@tonic-gate * Allocate a new cluster.
4510Sstevel@tonic-gate */
4520Sstevel@tonic-gate pc_cluster32_t
pc_alloccluster(struct pcfs * fsp,int zwrite)4530Sstevel@tonic-gate pc_alloccluster(
4540Sstevel@tonic-gate struct pcfs *fsp, /* file sys to allocate in */
4550Sstevel@tonic-gate int zwrite) /* boolean for writing zeroes */
4560Sstevel@tonic-gate {
4570Sstevel@tonic-gate pc_cluster32_t cn;
4580Sstevel@tonic-gate int error;
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate if (fsp->pcfs_fatp == (uchar_t *)0)
4610Sstevel@tonic-gate panic("pc_addcluster: no FAT");
4620Sstevel@tonic-gate
463*9251SMichael.Bergknoff@Sun.COM for (cn = fsp->pcfs_nxfrecls; pc_validcl(fsp, cn); cn++) {
4640Sstevel@tonic-gate if (pc_getcluster(fsp, cn) == PCF_FREECLUSTER) {
4650Sstevel@tonic-gate struct buf *bp;
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate if (IS_FAT32(fsp)) {
4680Sstevel@tonic-gate pc_setcluster(fsp, cn, PCF_LASTCLUSTERMARK32);
4695121Sfrankho if (fsp->pcfs_fsinfo.fs_free_clusters !=
4700Sstevel@tonic-gate FSINFO_UNKNOWN)
4715121Sfrankho fsp->pcfs_fsinfo.fs_free_clusters--;
4720Sstevel@tonic-gate } else
4730Sstevel@tonic-gate pc_setcluster(fsp, cn, PCF_LASTCLUSTERMARK);
4740Sstevel@tonic-gate if (zwrite) {
4750Sstevel@tonic-gate /*
4760Sstevel@tonic-gate * zero the new cluster
4770Sstevel@tonic-gate */
4780Sstevel@tonic-gate bp = ngeteblk(fsp->pcfs_clsize);
4790Sstevel@tonic-gate bp->b_edev = fsp->pcfs_xdev;
4800Sstevel@tonic-gate bp->b_dev = cmpdev(bp->b_edev);
4810Sstevel@tonic-gate bp->b_blkno = pc_cldaddr(fsp, cn);
4820Sstevel@tonic-gate clrbuf(bp);
4830Sstevel@tonic-gate bwrite2(bp);
4840Sstevel@tonic-gate error = geterror(bp);
4850Sstevel@tonic-gate brelse(bp);
4860Sstevel@tonic-gate if (error) {
4870Sstevel@tonic-gate pc_mark_irrecov(fsp);
4880Sstevel@tonic-gate return (PCF_ERRORCLUSTER);
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate fsp->pcfs_nxfrecls = cn + 1;
4920Sstevel@tonic-gate return (cn);
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate return (PCF_FREECLUSTER);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate * Get the number of clusters used by a file or subdirectory
5000Sstevel@tonic-gate */
5010Sstevel@tonic-gate int
pc_fileclsize(struct pcfs * fsp,pc_cluster32_t startcl,pc_cluster32_t * ncl)5020Sstevel@tonic-gate pc_fileclsize(
5030Sstevel@tonic-gate struct pcfs *fsp,
5042972Sfrankho pc_cluster32_t startcl, pc_cluster32_t *ncl)
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate int count = 0;
5070Sstevel@tonic-gate
5082972Sfrankho *ncl = 0;
5092972Sfrankho for (count = 0; pc_validcl(fsp, startcl);
5102972Sfrankho startcl = pc_getcluster(fsp, startcl)) {
5112972Sfrankho if (count++ >= fsp->pcfs_ncluster)
5122972Sfrankho return (EIO);
5130Sstevel@tonic-gate }
5142972Sfrankho *ncl = (pc_cluster32_t)count;
5152972Sfrankho
5162972Sfrankho return (0);
5170Sstevel@tonic-gate }
518