Line data Source code
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 0 : udf_rawnametounicode(u_int len, char *cs0string, unicode_t *transname)
59 : {
60 : unicode_t *origname = transname;
61 :
62 0 : if (len-- == 0)
63 0 : return (-1);
64 :
65 0 : switch (*cs0string++) {
66 : case 8: /* bytes string */
67 0 : while (len-- != 0)
68 0 : *transname++ = (unicode_t)*cs0string++;
69 : break;
70 : case 16: /* 16 bit unicode string */
71 0 : if (len & 1)
72 0 : return (-1);
73 0 : len >>= 1;
74 0 : while (len-- != 0) {
75 : unicode_t tmpchar;
76 :
77 0 : tmpchar = (unicode_t)*cs0string++;
78 0 : tmpchar = (tmpchar << 8) | (unicode_t)*cs0string++;
79 0 : *transname++ = tmpchar;
80 : }
81 : break;
82 : default:
83 0 : return (-1);
84 : }
85 :
86 0 : return (transname - origname);
87 0 : }
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 0 : udf_disklabelspoof(dev_t dev, void (*strat)(struct buf *),
95 : struct disklabel *lp)
96 : {
97 0 : char vid[32];
98 : int i, bsize = 2048, error = EINVAL;
99 : uint32_t sector = 256, mvds_start, mvds_end;
100 : struct buf *bp;
101 0 : struct anchor_vdp avdp;
102 : struct pri_vol_desc *pvd;
103 :
104 : /*
105 : * Get a buffer to work with.
106 : */
107 0 : bp = geteblk(bsize);
108 0 : bp->b_dev = dev;
109 :
110 : /*
111 : * Look for an Anchor Volume Descriptor at sector 256.
112 : */
113 0 : bp->b_blkno = sector * btodb(bsize);
114 0 : bp->b_bcount = bsize;
115 0 : CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
116 0 : SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
117 0 : bp->b_resid = bp->b_blkno / lp->d_secpercyl;
118 :
119 0 : (*strat)(bp);
120 0 : if (biowait(bp))
121 : goto out;
122 :
123 0 : if (udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR))
124 : goto out;
125 :
126 0 : bcopy(bp->b_data, &avdp, sizeof(avdp));
127 0 : mvds_start = letoh32(avdp.main_vds_ex.loc);
128 0 : 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 0 : for (sector = mvds_start; sector < mvds_end; sector++) {
134 0 : bp->b_blkno = sector * btodb(bsize);
135 0 : bp->b_bcount = bsize;
136 0 : CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
137 0 : SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
138 0 : bp->b_resid = bp->b_blkno / lp->d_secpercyl;
139 :
140 0 : (*strat)(bp);
141 0 : if (biowait(bp))
142 : goto out;
143 :
144 0 : pvd = (struct pri_vol_desc *)bp->b_data;
145 0 : 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 0 : if (sector == mvds_end)
153 : goto out;
154 :
155 : /*
156 : * Okay, it's a UDF volume. Spoof a disk label for it.
157 : */
158 0 : if (udf_transname(pvd->vol_id, vid, sizeof(pvd->vol_id) - 1, NULL))
159 0 : strlcpy(lp->d_typename, vid, sizeof(lp->d_typename));
160 :
161 0 : for (i = 0; i < MAXPARTITIONS; i++) {
162 0 : DL_SETPSIZE(&lp->d_partitions[i], 0);
163 0 : DL_SETPOFFSET(&lp->d_partitions[i], 0);
164 : }
165 :
166 : /*
167 : * Fake two partitions, 'a' and 'c'.
168 : */
169 0 : DL_SETPSIZE(&lp->d_partitions[0], DL_GETDSIZE(lp));
170 0 : lp->d_partitions[0].p_fstype = FS_UDF;
171 0 : DL_SETPSIZE(&lp->d_partitions[RAW_PART], DL_GETDSIZE(lp));
172 0 : lp->d_partitions[RAW_PART].p_fstype = FS_UDF;
173 0 : lp->d_npartitions = MAXPARTITIONS;
174 0 : lp->d_version = 1;
175 :
176 0 : lp->d_bbsize = 8192; /* Fake. */
177 0 : lp->d_sbsize = 64*1024; /* Fake. */
178 0 : lp->d_magic = DISKMAGIC;
179 0 : lp->d_magic2 = DISKMAGIC;
180 0 : lp->d_checksum = dkcksum(lp);
181 :
182 0 : error = 0;
183 : out:
184 0 : bp->b_flags |= B_INVAL;
185 0 : brelse(bp);
186 :
187 0 : return (error);
188 0 : }
189 :
190 : /* Get a vnode for the Virtual Allocation Table (VAT) */
191 : int
192 0 : udf_vat_get(struct umount *ump, uint32_t lb)
193 : {
194 0 : struct vnode *vp;
195 : struct unode *up;
196 : int error;
197 :
198 0 : error = udf_vget(ump->um_mountp, lb - ump->um_start - 3, &vp);
199 0 : if (error)
200 0 : return (error);
201 :
202 0 : up = VTOU(vp);
203 0 : up->u_vatlen = (letoh64(up->u_fentry->inf_len) - 36) >> 2;
204 :
205 0 : ump->um_vat = malloc(sizeof(struct unode), M_UDFMOUNT, M_WAITOK);
206 0 : *ump->um_vat = *up;
207 :
208 0 : ump->um_flags &= ~UDF_MNT_FIND_VAT;
209 0 : ump->um_flags |= UDF_MNT_USES_VAT;
210 :
211 0 : vput(vp);
212 :
213 0 : return (0);
214 0 : }
215 :
216 : /* Look up a sector in the VAT */
217 : int
218 0 : udf_vat_map(struct umount *ump, uint32_t *sector)
219 : {
220 : /* If there's no VAT, then it's easy */
221 0 : if (!(ump->um_flags & UDF_MNT_USES_VAT)) {
222 0 : *sector += ump->um_start;
223 0 : return (0);
224 : }
225 :
226 : /* Sanity check the given sector */
227 0 : if (*sector >= ump->um_vat->u_vatlen)
228 0 : return (EINVAL);
229 :
230 0 : return (udf_vat_read(ump, sector));
231 0 : }
232 :
233 : /* Read from the VAT */
234 : int
235 0 : udf_vat_read(struct umount *ump, uint32_t *sector)
236 : {
237 0 : struct buf *bp;
238 0 : uint8_t *data;
239 0 : int error, size;
240 :
241 0 : 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 0 : error = udf_readatoffset(ump->um_vat, &size, *sector << 2, &bp, &data);
248 0 : if (error) {
249 0 : if (bp != NULL)
250 0 : brelse(bp);
251 :
252 0 : return (error);
253 : }
254 :
255 : /* Make sure we read at least a whole entry */
256 0 : if (size < 4) {
257 0 : if (bp != NULL)
258 0 : brelse(bp);
259 :
260 0 : return (EINVAL);
261 : }
262 :
263 : /* Map the sector */
264 0 : *sector = letoh32(*(uint32_t *)data) + ump->um_start;
265 :
266 0 : brelse(bp);
267 :
268 0 : return (0);
269 0 : }
|