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