diff options
author | Pedro Martelletto <pedro@cvs.openbsd.org> | 2005-03-30 00:56:20 +0000 |
---|---|---|
committer | Pedro Martelletto <pedro@cvs.openbsd.org> | 2005-03-30 00:56:20 +0000 |
commit | 9ad16ca76bea66a3c14f2aeb246fbc0e822319e4 (patch) | |
tree | 107dd19250126ed0ad8525f4b9d80990085b854d | |
parent | de4115fc46aed3c4a916909a1a49c3ac7bbdb4ba (diff) |
Add disklabel spoofing code for UDF.
-rw-r--r-- | sys/isofs/udf/udf_vfsops.c | 101 |
1 files changed, 100 insertions, 1 deletions
diff --git a/sys/isofs/udf/udf_vfsops.c b/sys/isofs/udf/udf_vfsops.c index feadd8cb485..9516bf296b4 100644 --- a/sys/isofs/udf/udf_vfsops.c +++ b/sys/isofs/udf/udf_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udf_vfsops.c,v 1.1 2005/03/29 17:24:52 pedro Exp $ */ +/* $OpenBSD: udf_vfsops.c,v 1.2 2005/03/30 00:56:19 pedro Exp $ */ /* * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org> @@ -93,6 +93,7 @@ #include <sys/queue.h> #include <sys/vnode.h> #include <sys/endian.h> +#include <sys/disklabel.h> #include <miscfs/specfs/specdev.h> @@ -239,6 +240,104 @@ udf_checktag(struct desc_tag *tag, uint16_t id) return (EINVAL); } +/* + * Do a lazy probe on the underlying media to check if it's an UDF volume, in + * which case we fake a disklabel for it. + */ +int +udf_disklabelspoof(dev_t dev, void (*strat)(struct buf *), + struct disklabel *lp) +{ + char vid[32]; + int i, bsize = 2048, error = EINVAL; + uint32_t sector = 256, mvds_start, mvds_end; + struct buf *bp; + struct anchor_vdp avdp; + struct pri_vol_desc *pvd; + + /* + * Get a buffer to work with. + */ + bp = geteblk(bsize); + bp->b_dev = dev; + + /* + * Look for an Anchor Volume Descriptor at sector 256. + */ + bp->b_blkno = sector * btodb(bsize); + bp->b_bcount = bsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_resid = bp->b_blkno / lp->d_secpercyl; + + (*strat)(bp); + if (biowait(bp)) + goto out; + + if (udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)) + goto out; + + bcopy(bp->b_data, &avdp, sizeof(avdp)); + mvds_start = letoh32(avdp.main_vds_ex.loc); + mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len) - 1) / bsize; + + /* + * Then try to find a reference to a Primary Volume Descriptor. + */ + for (sector = mvds_start; sector < mvds_end; sector++) { + bp->b_blkno = sector * btodb(bsize); + bp->b_bcount = bsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_resid = bp->b_blkno / lp->d_secpercyl; + + (*strat)(bp); + if (biowait(bp)) + goto out; + + pvd = (struct pri_vol_desc *)bp->b_data; + if (!udf_checktag(&pvd->tag, TAGID_PRI_VOL)) + break; + } + + /* + * If we couldn't find a reference, bail out. + */ + if (sector == mvds_end) + goto out; + + /* + * Okay, it's an UDF volume. Spoof a disklabel for it. + */ + if (udf_transname(pvd->vol_id, vid, sizeof(pvd->vol_id), NULL)) + strlcpy(lp->d_typename, vid, sizeof(lp->d_typename)); + + for (i = 0; i < MAXPARTITIONS; i++) { + lp->d_partitions[i].p_size = 0; + lp->d_partitions[i].p_offset = 0; + } + + /* + * Fake two partitions, 'a' and 'c'. + */ + lp->d_partitions[0].p_size = lp->d_secperunit; + lp->d_partitions[0].p_fstype = FS_UDF; + lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; + lp->d_partitions[RAW_PART].p_fstype = FS_UDF; + lp->d_npartitions = RAW_PART + 1; + + lp->d_bbsize = 8192; /* Fake. */ + lp->d_sbsize = 64*1024; /* Fake. */ + lp->d_magic = DISKMAGIC; + lp->d_magic2 = DISKMAGIC; + lp->d_checksum = dkcksum(lp); + + error = 0; +out: + bp->b_flags |= B_INVAL; + brelse(bp); + + return (error); +} + int udf_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p) { struct buf *bp = NULL; |