1 /* $OpenBSD: udf_subr.c,v 1.18 2008/07/23 16:24:43 beck Exp $ */ 2 3 /* 4 * Copyright (c) 2006, Miodrag Vallat 5 * Copyright (c) 2006, Pedro Martelletto 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/buf.h> 32 #include <sys/kernel.h> 33 #include <sys/malloc.h> 34 #include <sys/mutex.h> 35 #include <sys/stat.h> 36 #include <sys/mount.h> 37 #include <sys/vnode.h> 38 #include <sys/dirent.h> 39 #include <sys/unistd.h> 40 #include <sys/disklabel.h> 41 42 #include <isofs/udf/ecma167-udf.h> 43 #include <isofs/udf/udf.h> 44 #include <isofs/udf/udf_extern.h> 45 46 int udf_vat_read(struct umount *, uint32_t *); 47 48 /* 49 * Convert a CS0 dstring to a 16-bit Unicode string. 50 * Returns the length of the Unicode string, in unicode characters (not 51 * bytes!), or -1 if an error arises. 52 * Note that the transname destination buffer is expected to be large 53 * enough to hold the result, and will not be terminated in any way. 54 */ 55 int 56 udf_rawnametounicode(u_int len, char *cs0string, unicode_t *transname) 57 { 58 unicode_t *origname = transname; 59 60 if (len-- == 0) 61 return (-1); 62 63 switch (*cs0string++) { 64 case 8: /* bytes string */ 65 while (len-- != 0) 66 *transname++ = (unicode_t)*cs0string++; 67 break; 68 case 16: /* 16 bit unicode string */ 69 if (len & 1) 70 return (-1); 71 len >>= 1; 72 while (len-- != 0) { 73 unicode_t tmpchar; 74 75 tmpchar = (unicode_t)*cs0string++; 76 tmpchar = (tmpchar << 8) | (unicode_t)*cs0string++; 77 *transname++ = tmpchar; 78 } 79 break; 80 default: 81 return (-1); 82 } 83 84 return (transname - origname); 85 } 86 87 /* 88 * Do a lazy probe on the underlying media to check if it's a UDF volume, in 89 * which case we fake a disk label for it. 90 */ 91 int 92 udf_disklabelspoof(dev_t dev, void (*strat)(struct buf *), 93 struct disklabel *lp) 94 { 95 char vid[32]; 96 int i, bsize = 2048, error = EINVAL; 97 uint32_t sector = 256, mvds_start, mvds_end; 98 struct buf *bp; 99 struct anchor_vdp avdp; 100 struct pri_vol_desc *pvd; 101 102 /* 103 * Get a buffer to work with. 104 */ 105 bp = geteblk(bsize); 106 bp->b_dev = dev; 107 108 /* 109 * Look for an Anchor Volume Descriptor at sector 256. 110 */ 111 bp->b_blkno = sector * btodb(bsize); 112 bp->b_bcount = bsize; 113 bp->b_flags |= (B_READ | B_RAW); 114 bp->b_resid = bp->b_blkno / lp->d_secpercyl; 115 116 (*strat)(bp); 117 if (biowait(bp)) 118 goto out; 119 120 if (udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)) 121 goto out; 122 123 bcopy(bp->b_data, &avdp, sizeof(avdp)); 124 mvds_start = letoh32(avdp.main_vds_ex.loc); 125 mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len) - 1) / bsize; 126 127 /* 128 * Then try to find a reference to a Primary Volume Descriptor. 129 */ 130 for (sector = mvds_start; sector < mvds_end; sector++) { 131 bp->b_blkno = sector * btodb(bsize); 132 bp->b_bcount = bsize; 133 bp->b_flags |= (B_READ | B_RAW); 134 bp->b_resid = bp->b_blkno / lp->d_secpercyl; 135 136 (*strat)(bp); 137 if (biowait(bp)) 138 goto out; 139 140 pvd = (struct pri_vol_desc *)bp->b_data; 141 if (!udf_checktag(&pvd->tag, TAGID_PRI_VOL)) 142 break; 143 } 144 145 /* 146 * If we couldn't find a reference, bail out. 147 */ 148 if (sector == mvds_end) 149 goto out; 150 151 /* 152 * Okay, it's a UDF volume. Spoof a disk label for it. 153 */ 154 if (udf_transname(pvd->vol_id, vid, sizeof(pvd->vol_id) - 1, NULL)) 155 strlcpy(lp->d_typename, vid, sizeof(lp->d_typename)); 156 157 for (i = 0; i < MAXPARTITIONS; i++) { 158 DL_SETPSIZE(&lp->d_partitions[i], 0); 159 DL_SETPOFFSET(&lp->d_partitions[i], 0); 160 } 161 162 /* 163 * Fake two partitions, 'a' and 'c'. 164 */ 165 DL_SETPSIZE(&lp->d_partitions[0], DL_GETDSIZE(lp)); 166 lp->d_partitions[0].p_fstype = FS_UDF; 167 DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); 168 lp->d_partitions[RAW_PART].p_fstype = FS_UDF; 169 lp->d_npartitions = RAW_PART + 1; 170 lp->d_version = 1; 171 172 lp->d_bbsize = 8192; /* Fake. */ 173 lp->d_sbsize = 64*1024; /* Fake. */ 174 lp->d_magic = DISKMAGIC; 175 lp->d_magic2 = DISKMAGIC; 176 lp->d_checksum = dkcksum(lp); 177 178 error = 0; 179 out: 180 bp->b_flags |= B_INVAL; 181 brelse(bp); 182 183 return (error); 184 } 185 186 /* Get a vnode for the Virtual Allocation Table (VAT) */ 187 int 188 udf_vat_get(struct umount *ump, uint32_t lb) 189 { 190 struct vnode *vp; 191 struct unode *up; 192 int error; 193 194 error = udf_vget(ump->um_mountp, lb - ump->um_start - 3, &vp); 195 if (error) 196 return (error); 197 198 up = VTOU(vp); 199 up->u_vatlen = (letoh64(up->u_fentry->inf_len) - 36) >> 2; 200 201 ump->um_vat = malloc(sizeof(struct unode), M_UDFMOUNT, M_WAITOK); 202 *ump->um_vat = *up; 203 204 ump->um_flags &= ~UDF_MNT_FIND_VAT; 205 ump->um_flags |= UDF_MNT_USES_VAT; 206 207 vput(vp); 208 209 return (0); 210 } 211 212 /* Look up a sector in the VAT */ 213 int 214 udf_vat_map(struct umount *ump, uint32_t *sector) 215 { 216 /* If there's no VAT, then it's easy */ 217 if (!(ump->um_flags & UDF_MNT_USES_VAT)) { 218 *sector += ump->um_start; 219 return (0); 220 } 221 222 /* Sanity check the given sector */ 223 if (*sector >= ump->um_vat->u_vatlen) 224 return (EINVAL); 225 226 return (udf_vat_read(ump, sector)); 227 } 228 229 /* Read from the VAT */ 230 int 231 udf_vat_read(struct umount *ump, uint32_t *sector) 232 { 233 struct buf *bp; 234 uint8_t *data; 235 int error, size; 236 237 size = 4; 238 239 /* 240 * Note that we rely on the buffer cache to keep frequently accessed 241 * buffers around to avoid reading them from the disk all the time. 242 */ 243 error = udf_readatoffset(ump->um_vat, &size, *sector << 2, &bp, &data); 244 if (error) { 245 if (bp != NULL) 246 brelse(bp); 247 248 return (error); 249 } 250 251 /* Make sure we read at least a whole entry */ 252 if (size < 4) { 253 if (bp != NULL) 254 brelse(bp); 255 256 return (EINVAL); 257 } 258 259 /* Map the sector */ 260 *sector = letoh32(*(uint32_t *)data) + ump->um_start; 261 262 brelse(bp); 263 264 return (0); 265 } 266