1 /* $OpenBSD: udf_subr.c,v 1.23 2014/11/03 21:28:35 tedu 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/disklabel.h> 40 41 #include <isofs/udf/ecma167-udf.h> 42 #include <isofs/udf/udf.h> 43 #include <isofs/udf/udf_extern.h> 44 45 int udf_vat_read(struct umount *, uint32_t *); 46 47 /* 48 * Convert a CS0 dstring to a 16-bit Unicode string. 49 * Returns the length of the Unicode string, in unicode characters (not 50 * bytes!), or -1 if an error arises. 51 * Note that the transname destination buffer is expected to be large 52 * enough to hold the result, and will not be terminated in any way. 53 */ 54 int 55 udf_rawnametounicode(u_int len, char *cs0string, unicode_t *transname) 56 { 57 unicode_t *origname = transname; 58 59 if (len-- == 0) 60 return (-1); 61 62 switch (*cs0string++) { 63 case 8: /* bytes string */ 64 while (len-- != 0) 65 *transname++ = (unicode_t)*cs0string++; 66 break; 67 case 16: /* 16 bit unicode string */ 68 if (len & 1) 69 return (-1); 70 len >>= 1; 71 while (len-- != 0) { 72 unicode_t tmpchar; 73 74 tmpchar = (unicode_t)*cs0string++; 75 tmpchar = (tmpchar << 8) | (unicode_t)*cs0string++; 76 *transname++ = tmpchar; 77 } 78 break; 79 default: 80 return (-1); 81 } 82 83 return (transname - origname); 84 } 85 86 /* 87 * Do a lazy probe on the underlying media to check if it's a UDF volume, in 88 * which case we fake a disk label for it. 89 */ 90 int 91 udf_disklabelspoof(dev_t dev, void (*strat)(struct buf *), 92 struct disklabel *lp) 93 { 94 char vid[32]; 95 int i, bsize = 2048, error = EINVAL; 96 uint32_t sector = 256, mvds_start, mvds_end; 97 struct buf *bp; 98 struct anchor_vdp avdp; 99 struct pri_vol_desc *pvd; 100 101 /* 102 * Get a buffer to work with. 103 */ 104 bp = geteblk(bsize); 105 bp->b_dev = dev; 106 107 /* 108 * Look for an Anchor Volume Descriptor at sector 256. 109 */ 110 bp->b_blkno = sector * btodb(bsize); 111 bp->b_bcount = bsize; 112 CLR(bp->b_flags, B_READ | B_WRITE | B_DONE); 113 SET(bp->b_flags, B_BUSY | 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 CLR(bp->b_flags, B_READ | B_WRITE | B_DONE); 134 SET(bp->b_flags, B_BUSY | B_READ | B_RAW); 135 bp->b_resid = bp->b_blkno / lp->d_secpercyl; 136 137 (*strat)(bp); 138 if (biowait(bp)) 139 goto out; 140 141 pvd = (struct pri_vol_desc *)bp->b_data; 142 if (!udf_checktag(&pvd->tag, TAGID_PRI_VOL)) 143 break; 144 } 145 146 /* 147 * If we couldn't find a reference, bail out. 148 */ 149 if (sector == mvds_end) 150 goto out; 151 152 /* 153 * Okay, it's a UDF volume. Spoof a disk label for it. 154 */ 155 if (udf_transname(pvd->vol_id, vid, sizeof(pvd->vol_id) - 1, NULL)) 156 strlcpy(lp->d_typename, vid, sizeof(lp->d_typename)); 157 158 for (i = 0; i < MAXPARTITIONS; i++) { 159 DL_SETPSIZE(&lp->d_partitions[i], 0); 160 DL_SETPOFFSET(&lp->d_partitions[i], 0); 161 } 162 163 /* 164 * Fake two partitions, 'a' and 'c'. 165 */ 166 DL_SETPSIZE(&lp->d_partitions[0], DL_GETDSIZE(lp)); 167 lp->d_partitions[0].p_fstype = FS_UDF; 168 DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp)); 169 lp->d_partitions[RAW_PART].p_fstype = FS_UDF; 170 lp->d_npartitions = MAXPARTITIONS; 171 lp->d_version = 1; 172 173 lp->d_bbsize = 8192; /* Fake. */ 174 lp->d_sbsize = 64*1024; /* Fake. */ 175 lp->d_magic = DISKMAGIC; 176 lp->d_magic2 = DISKMAGIC; 177 lp->d_checksum = dkcksum(lp); 178 179 error = 0; 180 out: 181 bp->b_flags |= B_INVAL; 182 brelse(bp); 183 184 return (error); 185 } 186 187 /* Get a vnode for the Virtual Allocation Table (VAT) */ 188 int 189 udf_vat_get(struct umount *ump, uint32_t lb) 190 { 191 struct vnode *vp; 192 struct unode *up; 193 int error; 194 195 error = udf_vget(ump->um_mountp, lb - ump->um_start - 3, &vp); 196 if (error) 197 return (error); 198 199 up = VTOU(vp); 200 up->u_vatlen = (letoh64(up->u_fentry->inf_len) - 36) >> 2; 201 202 ump->um_vat = malloc(sizeof(struct unode), M_UDFMOUNT, M_WAITOK); 203 *ump->um_vat = *up; 204 205 ump->um_flags &= ~UDF_MNT_FIND_VAT; 206 ump->um_flags |= UDF_MNT_USES_VAT; 207 208 vput(vp); 209 210 return (0); 211 } 212 213 /* Look up a sector in the VAT */ 214 int 215 udf_vat_map(struct umount *ump, uint32_t *sector) 216 { 217 /* If there's no VAT, then it's easy */ 218 if (!(ump->um_flags & UDF_MNT_USES_VAT)) { 219 *sector += ump->um_start; 220 return (0); 221 } 222 223 /* Sanity check the given sector */ 224 if (*sector >= ump->um_vat->u_vatlen) 225 return (EINVAL); 226 227 return (udf_vat_read(ump, sector)); 228 } 229 230 /* Read from the VAT */ 231 int 232 udf_vat_read(struct umount *ump, uint32_t *sector) 233 { 234 struct buf *bp; 235 uint8_t *data; 236 int error, size; 237 238 size = 4; 239 240 /* 241 * Note that we rely on the buffer cache to keep frequently accessed 242 * buffers around to avoid reading them from the disk all the time. 243 */ 244 error = udf_readatoffset(ump->um_vat, &size, *sector << 2, &bp, &data); 245 if (error) { 246 if (bp != NULL) 247 brelse(bp); 248 249 return (error); 250 } 251 252 /* Make sure we read at least a whole entry */ 253 if (size < 4) { 254 if (bp != NULL) 255 brelse(bp); 256 257 return (EINVAL); 258 } 259 260 /* Map the sector */ 261 *sector = letoh32(*(uint32_t *)data) + ump->um_start; 262 263 brelse(bp); 264 265 return (0); 266 } 267