/* $OpenBSD: udf_subr.c,v 1.4 2006/01/15 00:04:42 pedro Exp $ */ /* * Copyright (c) 2006, Miodrag Vallat * Copyright (c) 2006, Pedro Martelletto * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Convert a CS0 dstring to a 16-bit Unicode string. * Returns the length of the Unicode string, in unicode characters (not * bytes!), or -1 if an error arises. * Note that the transname destination buffer is expected to be large * enough to hold the result, and will not be terminated in any way. */ int udf_rawnametounicode(u_int len, char *cs0string, unicode_t *transname) { unicode_t *origname = transname; if (len-- == 0) return (-1); switch (*cs0string++) { case 8: /* bytes string */ while (len-- != 0) *transname++ = (unicode_t)*cs0string++; break; case 16: /* 16 bit unicode string */ if (len & 1) return (-1); len >>= 1; while (len-- != 0) { unicode_t tmpchar; tmpchar = (unicode_t)*cs0string++; tmpchar = (tmpchar << 8) | (unicode_t)*cs0string++; *transname++ = tmpchar; } break; default: return (-1); } return (transname - origname); } /* * Do a lazy probe on the underlying media to check if it's a UDF volume, in * which case we fake a disk label 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 a UDF volume. Spoof a disk label for it. */ if (udf_transname(pvd->vol_id, vid, sizeof(pvd->vol_id) - 1, 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); }