summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Martelletto <pedro@cvs.openbsd.org>2005-03-30 00:56:20 +0000
committerPedro Martelletto <pedro@cvs.openbsd.org>2005-03-30 00:56:20 +0000
commit9ad16ca76bea66a3c14f2aeb246fbc0e822319e4 (patch)
tree107dd19250126ed0ad8525f4b9d80990085b854d
parentde4115fc46aed3c4a916909a1a49c3ac7bbdb4ba (diff)
Add disklabel spoofing code for UDF.
-rw-r--r--sys/isofs/udf/udf_vfsops.c101
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;