xref: /openbsd-src/sys/isofs/udf/udf_subr.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: udf_subr.c,v 1.22 2011/04/16 03:21:16 krw 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 	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
114 	SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
115 	bp->b_resid = bp->b_blkno / lp->d_secpercyl;
116 
117 	(*strat)(bp);
118 	if (biowait(bp))
119 		goto out;
120 
121 	if (udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR))
122 		goto out;
123 
124 	bcopy(bp->b_data, &avdp, sizeof(avdp));
125 	mvds_start = letoh32(avdp.main_vds_ex.loc);
126 	mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len) - 1) / bsize;
127 
128 	/*
129 	 * Then try to find a reference to a Primary Volume Descriptor.
130 	 */
131 	for (sector = mvds_start; sector < mvds_end; sector++) {
132 		bp->b_blkno = sector * btodb(bsize);
133 		bp->b_bcount = bsize;
134 		CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
135 		SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
136 		bp->b_resid = bp->b_blkno / lp->d_secpercyl;
137 
138 		(*strat)(bp);
139 		if (biowait(bp))
140 			goto out;
141 
142 		pvd = (struct pri_vol_desc *)bp->b_data;
143 		if (!udf_checktag(&pvd->tag, TAGID_PRI_VOL))
144 			break;
145 	}
146 
147 	/*
148 	 * If we couldn't find a reference, bail out.
149 	 */
150 	if (sector == mvds_end)
151 		goto out;
152 
153 	/*
154 	 * Okay, it's a UDF volume. Spoof a disk label for it.
155 	 */
156 	if (udf_transname(pvd->vol_id, vid, sizeof(pvd->vol_id) - 1, NULL))
157 		strlcpy(lp->d_typename, vid, sizeof(lp->d_typename));
158 
159 	for (i = 0; i < MAXPARTITIONS; i++) {
160 		DL_SETPSIZE(&lp->d_partitions[i], 0);
161 		DL_SETPOFFSET(&lp->d_partitions[i], 0);
162 	}
163 
164 	/*
165 	 * Fake two partitions, 'a' and 'c'.
166 	 */
167 	DL_SETPSIZE(&lp->d_partitions[0], DL_GETDSIZE(lp));
168 	lp->d_partitions[0].p_fstype = FS_UDF;
169 	DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
170 	lp->d_partitions[RAW_PART].p_fstype = FS_UDF;
171 	lp->d_npartitions = MAXPARTITIONS;
172 	lp->d_version = 1;
173 
174 	lp->d_bbsize = 8192;	/* Fake. */
175 	lp->d_sbsize = 64*1024;	/* Fake. */
176 	lp->d_magic = DISKMAGIC;
177 	lp->d_magic2 = DISKMAGIC;
178 	lp->d_checksum = dkcksum(lp);
179 
180 	error = 0;
181 out:
182 	bp->b_flags |= B_INVAL;
183 	brelse(bp);
184 
185 	return (error);
186 }
187 
188 /* Get a vnode for the Virtual Allocation Table (VAT) */
189 int
190 udf_vat_get(struct umount *ump, uint32_t lb)
191 {
192 	struct vnode *vp;
193 	struct unode *up;
194 	int error;
195 
196 	error = udf_vget(ump->um_mountp, lb - ump->um_start - 3, &vp);
197 	if (error)
198 		return (error);
199 
200 	up = VTOU(vp);
201 	up->u_vatlen = (letoh64(up->u_fentry->inf_len) - 36) >> 2;
202 
203 	ump->um_vat = malloc(sizeof(struct unode), M_UDFMOUNT, M_WAITOK);
204        *ump->um_vat = *up;
205 
206 	ump->um_flags &= ~UDF_MNT_FIND_VAT;
207 	ump->um_flags |=  UDF_MNT_USES_VAT;
208 
209 	vput(vp);
210 
211 	return (0);
212 }
213 
214 /* Look up a sector in the VAT */
215 int
216 udf_vat_map(struct umount *ump, uint32_t *sector)
217 {
218 	/* If there's no VAT, then it's easy */
219 	if (!(ump->um_flags & UDF_MNT_USES_VAT)) {
220 		*sector += ump->um_start;
221 		return (0);
222 	}
223 
224 	/* Sanity check the given sector */
225 	if (*sector >= ump->um_vat->u_vatlen)
226 		return (EINVAL);
227 
228 	return (udf_vat_read(ump, sector));
229 }
230 
231 /* Read from the VAT */
232 int
233 udf_vat_read(struct umount *ump, uint32_t *sector)
234 {
235 	struct buf *bp;
236 	uint8_t *data;
237 	int error, size;
238 
239 	size = 4;
240 
241 	/*
242 	 * Note that we rely on the buffer cache to keep frequently accessed
243 	 * buffers around to avoid reading them from the disk all the time.
244 	 */
245 	error = udf_readatoffset(ump->um_vat, &size, *sector << 2, &bp, &data);
246 	if (error) {
247 		if (bp != NULL)
248 			brelse(bp);
249 
250 		return (error);
251 	}
252 
253 	/* Make sure we read at least a whole entry */
254 	if (size < 4) {
255 		if (bp != NULL)
256 			brelse(bp);
257 
258 		return (EINVAL);
259 	}
260 
261 	/* Map the sector */
262 	*sector = letoh32(*(uint32_t *)data) + ump->um_start;
263 
264 	brelse(bp);
265 
266 	return (0);
267 }
268