File: | isofs/udf/udf_vfsops.c |
Warning: | line 327, column 8 Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: udf_vfsops.c,v 1.70 2022/01/11 03:13:59 jsg Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org> |
5 | * All rights reserved. |
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 AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. |
27 | * |
28 | * $FreeBSD: src/sys/fs/udf/udf_vfsops.c,v 1.25 2005/01/25 15:52:03 phk Exp $ |
29 | */ |
30 | |
31 | /* |
32 | * Ported to OpenBSD by Pedro Martelletto in February 2005. |
33 | */ |
34 | |
35 | /* |
36 | * Ok, here's how it goes. The UDF specs are pretty clear on how each data |
37 | * structure is made up, but not very clear on how they relate to each other. |
38 | * Here is the skinny... This demonstrates a filesystem with one file in the |
39 | * root directory. Subdirectories are treated just as normal files, but they |
40 | * have File Id Descriptors of their children as their file data. As for the |
41 | * Anchor Volume Descriptor Pointer, it can exist in two of the following three |
42 | * places: sector 256, sector n (the max sector of the disk), or sector |
43 | * n - 256. It's a pretty good bet that one will exist at sector 256 though. |
44 | * One caveat is unclosed CD media. For that, sector 256 cannot be written, |
45 | * so the Anchor Volume Descriptor Pointer can exist at sector 512 until the |
46 | * media is closed. |
47 | */ |
48 | |
49 | #include <sys/param.h> |
50 | #include <sys/systm.h> |
51 | #include <sys/uio.h> |
52 | #include <sys/buf.h> |
53 | #include <sys/dirent.h> |
54 | #include <sys/fcntl.h> |
55 | #include <sys/kernel.h> |
56 | #include <sys/malloc.h> |
57 | #include <sys/mutex.h> |
58 | #include <sys/mount.h> |
59 | #include <sys/namei.h> |
60 | #include <sys/pool.h> |
61 | #include <sys/proc.h> |
62 | #include <sys/lock.h> |
63 | #include <sys/queue.h> |
64 | #include <sys/vnode.h> |
65 | #include <sys/lock.h> |
66 | #include <sys/endian.h> |
67 | #include <sys/specdev.h> |
68 | |
69 | #include <crypto/siphash.h> |
70 | |
71 | #include <isofs/udf/ecma167-udf.h> |
72 | #include <isofs/udf/udf.h> |
73 | #include <isofs/udf/udf_extern.h> |
74 | |
75 | struct pool udf_trans_pool; |
76 | struct pool unode_pool; |
77 | struct pool udf_ds_pool; |
78 | |
79 | int udf_find_partmaps(struct umount *, struct logvol_desc *); |
80 | int udf_get_vpartmap(struct umount *, struct part_map_virt *); |
81 | int udf_get_spartmap(struct umount *, struct part_map_spare *); |
82 | int udf_get_mpartmap(struct umount *, struct part_map_meta *); |
83 | int udf_mountfs(struct vnode *, struct mount *, uint32_t, struct proc *); |
84 | |
85 | const struct vfsops udf_vfsops = { |
86 | .vfs_mount = udf_mount, |
87 | .vfs_start = udf_start, |
88 | .vfs_unmount = udf_unmount, |
89 | .vfs_root = udf_root, |
90 | .vfs_quotactl = udf_quotactl, |
91 | .vfs_statfs = udf_statfs, |
92 | .vfs_sync = udf_sync, |
93 | .vfs_vget = udf_vget, |
94 | .vfs_fhtovp = udf_fhtovp, |
95 | .vfs_vptofh = udf_vptofh, |
96 | .vfs_init = udf_init, |
97 | .vfs_sysctl = udf_sysctl, |
98 | .vfs_checkexp = udf_checkexp, |
99 | }; |
100 | |
101 | int |
102 | udf_init(struct vfsconf *foo) |
103 | { |
104 | pool_init(&udf_trans_pool, MAXNAMLEN255 * sizeof(unicode_t), 0, IPL_NONE0x0, |
105 | PR_WAITOK0x0001, "udftrpl", NULL((void *)0)); |
106 | pool_init(&unode_pool, sizeof(struct unode), 0, IPL_NONE0x0, |
107 | PR_WAITOK0x0001, "udfndpl", NULL((void *)0)); |
108 | pool_init(&udf_ds_pool, sizeof(struct udf_dirstream), 0, IPL_NONE0x0, |
109 | PR_WAITOK0x0001, "udfdspl", NULL((void *)0)); |
110 | |
111 | return (0); |
112 | } |
113 | |
114 | int |
115 | udf_start(struct mount *mp, int flags, struct proc *p) |
116 | { |
117 | return (0); |
118 | } |
119 | |
120 | int |
121 | udf_mount(struct mount *mp, const char *path, void *data, |
122 | struct nameidata *ndp, struct proc *p) |
123 | { |
124 | struct vnode *devvp; /* vnode of the mount device */ |
125 | struct udf_args *args = data; |
126 | char fspec[MNAMELEN90]; |
127 | int error; |
128 | |
129 | if ((mp->mnt_flag & MNT_RDONLY0x00000001) == 0) { |
130 | mp->mnt_flag |= MNT_RDONLY0x00000001; |
131 | #ifdef UDF_DEBUG |
132 | printf("udf_mount: enforcing read-only mode\n"); |
133 | #endif |
134 | } |
135 | |
136 | /* |
137 | * No root filesystem support. Probably not a big deal, since the |
138 | * bootloader doesn't understand UDF. |
139 | */ |
140 | if (mp->mnt_flag & MNT_ROOTFS0x00004000) |
141 | return (EOPNOTSUPP45); |
142 | |
143 | /* |
144 | * If updating, check whether changing from read-only to |
145 | * read/write; if there is no device name, that's all we do. |
146 | */ |
147 | if (mp->mnt_flag & MNT_UPDATE0x00010000) { |
148 | return (0); |
149 | } |
150 | |
151 | error = copyinstr(args->fspec, fspec, sizeof(fspec), NULL((void *)0)); |
152 | if (error) |
153 | return (error); |
154 | |
155 | NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, p)ndinitat(ndp, 0, 0x0040, UIO_SYSSPACE, -100, fspec, p); |
156 | if ((error = namei(ndp))) |
157 | return (error); |
158 | |
159 | devvp = ndp->ni_vp; |
160 | if (devvp->v_type != VBLK) { |
161 | vrele(devvp); |
162 | return (ENOTBLK15); |
163 | } |
164 | |
165 | if (major(devvp->v_rdev)(((unsigned)(devvp->v_un.vu_specinfo->si_rdev) >> 8) & 0xff) >= nblkdev) { |
166 | vrele(devvp); |
167 | return (ENXIO6); |
168 | } |
169 | |
170 | if ((error = udf_mountfs(devvp, mp, args->lastblock, p))) { |
171 | vrele(devvp); |
172 | return (error); |
173 | } |
174 | |
175 | /* |
176 | * Keep a copy of the mount information. |
177 | */ |
178 | bzero(mp->mnt_stat.f_mntonname, MNAMELEN)__builtin_bzero((mp->mnt_stat.f_mntonname), (90)); |
179 | strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN90); |
180 | bzero(mp->mnt_stat.f_mntfromname, MNAMELEN)__builtin_bzero((mp->mnt_stat.f_mntfromname), (90)); |
181 | strlcpy(mp->mnt_stat.f_mntfromname, fspec, MNAMELEN90); |
182 | bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN)__builtin_bzero((mp->mnt_stat.f_mntfromspec), (90)); |
183 | strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN90); |
184 | |
185 | return (0); |
186 | }; |
187 | |
188 | /* |
189 | * Check the descriptor tag for both the correct id and correct checksum. |
190 | * Return zero if all is good, EINVAL if not. |
191 | */ |
192 | int |
193 | udf_checktag(struct desc_tag *tag, uint16_t id) |
194 | { |
195 | uint8_t *itag; |
196 | uint8_t i, cksum = 0; |
197 | |
198 | itag = (uint8_t *)tag; |
199 | |
200 | if (letoh16(tag->id)((__uint16_t)(tag->id)) != id) |
201 | return (EINVAL22); |
202 | |
203 | for (i = 0; i < 15; i++) |
204 | cksum = cksum + itag[i]; |
205 | cksum = cksum - itag[4]; |
206 | |
207 | if (cksum == tag->cksum) |
208 | return (0); |
209 | |
210 | return (EINVAL22); |
211 | } |
212 | |
213 | int |
214 | udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p) |
215 | { |
216 | struct buf *bp = NULL((void *)0); |
217 | struct anchor_vdp avdp; |
218 | struct umount *ump = NULL((void *)0); |
219 | struct part_desc *pd; |
220 | struct logvol_desc *lvd; |
221 | struct fileset_desc *fsd; |
222 | struct extfile_entry *xfentry; |
223 | struct file_entry *fentry; |
224 | uint32_t sector, size, mvds_start, mvds_end; |
225 | uint32_t fsd_offset = 0; |
226 | uint16_t part_num = 0, fsd_part = 0; |
227 | int error = EINVAL22; |
228 | int logvol_found = 0, part_found = 0, fsd_found = 0; |
229 | int bsize; |
230 | |
231 | /* |
232 | * Disallow multiple mounts of the same device. |
233 | * Disallow mounting of a device that is currently in use |
234 | * (except for root, which might share swap device for miniroot). |
235 | * Flush out any old buffers remaining from a previous use. |
236 | */ |
237 | if ((error = vfs_mountedon(devvp))) |
238 | return (error); |
239 | if (vcount(devvp) > 1 && devvp != rootvp) |
240 | return (EBUSY16); |
241 | vn_lock(devvp, LK_EXCLUSIVE0x0001UL | LK_RETRY0x2000UL); |
242 | error = vinvalbuf(devvp, V_SAVE0x0001, p->p_ucred, p, 0, INFSLP0xffffffffffffffffULL); |
243 | VOP_UNLOCK(devvp); |
244 | if (error) |
245 | return (error); |
246 | |
247 | error = VOP_OPEN(devvp, FREAD0x0001, FSCRED((struct ucred *)-2), p); |
248 | if (error) |
249 | return (error); |
250 | |
251 | ump = malloc(sizeof(*ump), M_UDFMOUNT140, M_WAITOK0x0001 | M_ZERO0x0008); |
252 | |
253 | mp->mnt_data = ump; |
254 | mp->mnt_stat.f_fsid.val[0] = devvp->v_rdevv_un.vu_specinfo->si_rdev; |
255 | mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; |
256 | mp->mnt_stat.f_namemax = NAME_MAX255; |
257 | mp->mnt_flag |= MNT_LOCAL0x00001000; |
258 | |
259 | ump->um_mountp = mp; |
260 | ump->um_dev = devvp->v_rdevv_un.vu_specinfo->si_rdev; |
261 | ump->um_devvp = devvp; |
262 | |
263 | bsize = 2048; /* Should probe the media for its size. */ |
264 | |
265 | /* |
266 | * Get the Anchor Volume Descriptor Pointer from sector 256. |
267 | * Should also check sector n - 256, n, and 512. |
268 | */ |
269 | sector = 256; |
270 | if ((error = bread(devvp, sector * btodb(bsize)((bsize) >> 9), bsize, &bp)) != 0) |
271 | goto bail; |
272 | if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR))) |
273 | goto bail; |
274 | |
275 | bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp)); |
276 | brelse(bp); |
277 | bp = NULL((void *)0); |
278 | |
279 | /* |
280 | * Extract the Partition Descriptor and Logical Volume Descriptor |
281 | * from the Volume Descriptor Sequence. |
282 | * Should we care about the partition type right now? |
283 | * What about multiple partitions? |
284 | */ |
285 | mvds_start = letoh32(avdp.main_vds_ex.loc)((__uint32_t)(avdp.main_vds_ex.loc)); |
286 | mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len)((__uint32_t)(avdp.main_vds_ex.len)) - 1) / bsize; |
287 | for (sector = mvds_start; sector < mvds_end; sector++) { |
288 | if ((error = bread(devvp, sector * btodb(bsize)((bsize) >> 9), bsize, |
289 | &bp)) != 0) { |
290 | printf("Can't read sector %d of VDS\n", sector); |
291 | goto bail; |
292 | } |
293 | lvd = (struct logvol_desc *)bp->b_data; |
294 | if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) { |
295 | ump->um_bsize = letoh32(lvd->lb_size)((__uint32_t)(lvd->lb_size)); |
296 | ump->um_bmask = ump->um_bsize - 1; |
297 | ump->um_bshift = ffs(ump->um_bsize) - 1; |
298 | fsd_part = letoh16(lvd->_lvd_use.fsd_loc.loc.part_num)((__uint16_t)(lvd->_lvd_use.fsd_loc.loc.part_num)); |
299 | fsd_offset = letoh32(lvd->_lvd_use.fsd_loc.loc.lb_num)((__uint32_t)(lvd->_lvd_use.fsd_loc.loc.lb_num)); |
300 | if (udf_find_partmaps(ump, lvd)) |
301 | break; |
302 | logvol_found = 1; |
303 | } |
304 | pd = (struct part_desc *)bp->b_data; |
305 | if (!udf_checktag(&pd->tag, TAGID_PARTITION)) { |
306 | part_found = 1; |
307 | part_num = letoh16(pd->part_num)((__uint16_t)(pd->part_num)); |
308 | ump->um_len = ump->um_reallen = letoh32(pd->part_len)((__uint32_t)(pd->part_len)); |
309 | ump->um_start = ump->um_realstart = letoh32(pd->start_loc)((__uint32_t)(pd->start_loc)); |
310 | } |
311 | |
312 | brelse(bp); |
313 | bp = NULL((void *)0); |
314 | if ((part_found) && (logvol_found)) |
315 | break; |
316 | } |
317 | |
318 | if (!part_found || !logvol_found) { |
319 | error = EINVAL22; |
320 | goto bail; |
321 | } |
322 | |
323 | if (ISSET(ump->um_flags, UDF_MNT_USES_META)((ump->um_flags) & (0x04))) { |
324 | /* Read Metadata File 'File Entry' to find Metadata file. */ |
325 | struct long_ad *la; |
326 | sector = ump->um_start + ump->um_meta_start; /* Set in udf_get_mpartmap() */ |
327 | if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)bread(devvp, ((daddr_t)(sector) << ump->um_bshift) / (1 << 9), ump->um_bsize, &bp)) != 0) { |
Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' | |
328 | printf("Cannot read sector %d for Metadata File Entry\n", sector); |
329 | error = EINVAL22; |
330 | goto bail; |
331 | } |
332 | xfentry = (struct extfile_entry *)bp->b_data; |
333 | fentry = (struct file_entry *)bp->b_data; |
334 | if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0) |
335 | la = (struct long_ad *)&xfentry->data[letoh32(xfentry->l_ea)((__uint32_t)(xfentry->l_ea))]; |
336 | else if (udf_checktag(&fentry->tag, TAGID_FENTRY) == 0) |
337 | la = (struct long_ad *)&fentry->data[letoh32(fentry->l_ea)((__uint32_t)(fentry->l_ea))]; |
338 | else { |
339 | printf("Invalid Metadata File FE @ sector %d! (tag.id %d)\n", |
340 | sector, fentry->tag.id); |
341 | error = EINVAL22; |
342 | goto bail; |
343 | } |
344 | ump->um_meta_start = letoh32(la->loc.lb_num)((__uint32_t)(la->loc.lb_num)); |
345 | ump->um_meta_len = letoh32(la->len)((__uint32_t)(la->len)); |
346 | if (bp != NULL((void *)0)) { |
347 | brelse(bp); |
348 | bp = NULL((void *)0); |
349 | } |
350 | } else if (fsd_part != part_num) { |
351 | printf("FSD does not lie within the partition!\n"); |
352 | error = EINVAL22; |
353 | goto bail; |
354 | } |
355 | |
356 | mtx_init(&ump->um_hashmtx, IPL_NONE)do { (void)(((void *)0)); (void)(0); __mtx_init((&ump-> um_hashmtx), ((((0x0)) > 0x0 && ((0x0)) < 0x9) ? 0x9 : ((0x0)))); } while (0); |
357 | ump->um_hashtbl = hashinit(UDF_HASHTBLSIZE100, M_UDFMOUNT140, M_WAITOK0x0001, |
358 | &ump->um_hashsz); |
359 | arc4random_buf(&ump->um_hashkey, sizeof(ump->um_hashkey)); |
360 | |
361 | /* Get the VAT, if needed */ |
362 | if (ump->um_flags & UDF_MNT_FIND_VAT0x01) { |
363 | error = udf_vat_get(ump, lb); |
364 | if (error) |
365 | goto bail; |
366 | } |
367 | |
368 | /* |
369 | * Grab the Fileset Descriptor |
370 | * Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing |
371 | * me in the right direction here. |
372 | */ |
373 | |
374 | if (ISSET(ump->um_flags, UDF_MNT_USES_META)((ump->um_flags) & (0x04))) |
375 | sector = ump->um_meta_start; |
376 | else |
377 | sector = fsd_offset; |
378 | udf_vat_map(ump, §or); |
379 | if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)bread(devvp, ((daddr_t)(sector) << ump->um_bshift) / (1 << 9), ump->um_bsize, &bp)) != 0) { |
380 | printf("Cannot read sector %d of FSD\n", sector); |
381 | goto bail; |
382 | } |
383 | fsd = (struct fileset_desc *)bp->b_data; |
384 | if (!udf_checktag(&fsd->tag, TAGID_FSD)) { |
385 | fsd_found = 1; |
386 | bcopy(&fsd->rootdir_icb, &ump->um_root_icb, |
387 | sizeof(struct long_ad)); |
388 | if (ISSET(ump->um_flags, UDF_MNT_USES_META)((ump->um_flags) & (0x04))) { |
389 | ump->um_root_icb.loc.lb_num += ump->um_meta_start; |
390 | ump->um_root_icb.loc.part_num = part_num; |
391 | } |
392 | } |
393 | |
394 | brelse(bp); |
395 | bp = NULL((void *)0); |
396 | |
397 | if (!fsd_found) { |
398 | printf("Couldn't find the fsd\n"); |
399 | error = EINVAL22; |
400 | goto bail; |
401 | } |
402 | |
403 | /* |
404 | * Find the file entry for the root directory. |
405 | */ |
406 | sector = letoh32(ump->um_root_icb.loc.lb_num)((__uint32_t)(ump->um_root_icb.loc.lb_num)); |
407 | size = letoh32(ump->um_root_icb.len)((__uint32_t)(ump->um_root_icb.len)); |
408 | udf_vat_map(ump, §or); |
409 | if ((error = udf_readlblks(ump, sector, size, &bp)) != 0) { |
410 | printf("Cannot read sector %d\n", sector); |
411 | goto bail; |
412 | } |
413 | |
414 | xfentry = (struct extfile_entry *)bp->b_data; |
415 | fentry = (struct file_entry *)bp->b_data; |
416 | error = udf_checktag(&xfentry->tag, TAGID_EXTFENTRY); |
417 | if (error) { |
418 | error = udf_checktag(&fentry->tag, TAGID_FENTRY); |
419 | if (error) { |
420 | printf("Invalid root file entry!\n"); |
421 | goto bail; |
422 | } |
423 | } |
424 | |
425 | brelse(bp); |
426 | bp = NULL((void *)0); |
427 | |
428 | devvp->v_specmountpointv_un.vu_specinfo->si_mountpoint = mp; |
429 | |
430 | return (0); |
431 | |
432 | bail: |
433 | if (ump != NULL((void *)0)) { |
434 | hashfree(ump->um_hashtbl, UDF_HASHTBLSIZE100, M_UDFMOUNT140); |
435 | free(ump, M_UDFMOUNT140, 0); |
436 | mp->mnt_data = NULL((void *)0); |
437 | mp->mnt_flag &= ~MNT_LOCAL0x00001000; |
438 | } |
439 | if (devvp->v_specinfov_un.vu_specinfo) |
440 | devvp->v_specmountpointv_un.vu_specinfo->si_mountpoint = NULL((void *)0); |
441 | if (bp != NULL((void *)0)) |
442 | brelse(bp); |
443 | |
444 | vn_lock(devvp, LK_EXCLUSIVE0x0001UL|LK_RETRY0x2000UL); |
445 | VOP_CLOSE(devvp, FREAD0x0001, FSCRED((struct ucred *)-2), p); |
446 | VOP_UNLOCK(devvp); |
447 | |
448 | return (error); |
449 | } |
450 | |
451 | int |
452 | udf_unmount(struct mount *mp, int mntflags, struct proc *p) |
453 | { |
454 | struct umount *ump; |
455 | struct vnode *devvp; |
456 | int error, flags = 0; |
457 | |
458 | ump = VFSTOUDFFS(mp)((struct umount *)((mp)->mnt_data)); |
459 | devvp = ump->um_devvp; |
460 | |
461 | if (mntflags & MNT_FORCE0x00080000) |
462 | flags |= FORCECLOSE0x0002; |
463 | |
464 | if ((error = vflush(mp, NULL((void *)0), flags))) |
465 | return (error); |
466 | |
467 | vn_lock(devvp, LK_EXCLUSIVE0x0001UL | LK_RETRY0x2000UL); |
468 | vinvalbuf(devvp, V_SAVE0x0001, NOCRED((struct ucred *)-1), p, 0, INFSLP0xffffffffffffffffULL); |
469 | (void)VOP_CLOSE(devvp, FREAD0x0001, NOCRED((struct ucred *)-1), p); |
470 | VOP_UNLOCK(devvp); |
471 | |
472 | devvp->v_specmountpointv_un.vu_specinfo->si_mountpoint = NULL((void *)0); |
473 | vrele(devvp); |
474 | |
475 | if (ump->um_flags & UDF_MNT_USES_VAT0x02) |
476 | free(ump->um_vat, M_UDFMOUNT140, 0); |
477 | |
478 | if (ump->um_stbl != NULL((void *)0)) |
479 | free(ump->um_stbl, M_UDFMOUNT140, 0); |
480 | |
481 | hashfree(ump->um_hashtbl, UDF_HASHTBLSIZE100, M_UDFMOUNT140); |
482 | free(ump, M_UDFMOUNT140, 0); |
483 | |
484 | mp->mnt_data = NULL((void *)0); |
485 | mp->mnt_flag &= ~MNT_LOCAL0x00001000; |
486 | |
487 | return (0); |
488 | } |
489 | |
490 | int |
491 | udf_root(struct mount *mp, struct vnode **vpp) |
492 | { |
493 | struct umount *ump; |
494 | struct vnode *vp; |
495 | udfino_t id; |
496 | int error; |
497 | |
498 | ump = VFSTOUDFFS(mp)((struct umount *)((mp)->mnt_data)); |
499 | |
500 | id = udf_getid(&ump->um_root_icb); |
501 | |
502 | error = udf_vget(mp, id, vpp); |
503 | if (error) |
504 | return (error); |
505 | |
506 | vp = *vpp; |
507 | vp->v_flag |= VROOT0x0001; |
508 | |
509 | return (0); |
510 | } |
511 | |
512 | int |
513 | udf_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg, |
514 | struct proc *p) |
515 | { |
516 | return (EOPNOTSUPP45); |
517 | } |
518 | |
519 | int |
520 | udf_statfs(struct mount *mp, struct statfs *sbp, struct proc *p) |
521 | { |
522 | struct umount *ump; |
523 | |
524 | ump = VFSTOUDFFS(mp)((struct umount *)((mp)->mnt_data)); |
525 | |
526 | sbp->f_bsize = ump->um_bsize; |
527 | sbp->f_iosize = ump->um_bsize; |
528 | sbp->f_blocks = ump->um_len; |
529 | sbp->f_bfree = 0; |
530 | sbp->f_bavail = 0; |
531 | sbp->f_files = 0; |
532 | sbp->f_ffree = 0; |
533 | sbp->f_favail = 0; |
534 | copy_statfs_info(sbp, mp); |
535 | |
536 | return (0); |
537 | } |
538 | |
539 | int |
540 | udf_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred, struct proc *p) |
541 | { |
542 | return (0); |
543 | } |
544 | |
545 | int |
546 | udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp) |
547 | { |
548 | struct buf *bp; |
549 | struct vnode *devvp; |
550 | struct umount *ump; |
551 | struct proc *p; |
552 | struct vnode *vp, *nvp; |
553 | struct unode *up; |
554 | struct extfile_entry *xfe; |
555 | struct file_entry *fe; |
556 | uint32_t sector; |
557 | int error, size; |
558 | |
559 | if (ino > (udfino_t)-1) |
560 | panic("udf_vget: alien ino_t %llu", (unsigned long long)ino); |
561 | |
562 | p = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc; |
563 | bp = NULL((void *)0); |
564 | *vpp = NULL((void *)0); |
565 | ump = VFSTOUDFFS(mp)((struct umount *)((mp)->mnt_data)); |
566 | |
567 | /* See if we already have this in the cache */ |
568 | if ((error = udf_hashlookup(ump, ino, LK_EXCLUSIVE0x0001UL, vpp)) != 0) |
569 | return (error); |
570 | if (*vpp != NULL((void *)0)) |
571 | return (0); |
572 | |
573 | /* |
574 | * Allocate memory and check the tag id's before grabbing a new |
575 | * vnode, since it's hard to roll back if there is a problem. |
576 | */ |
577 | up = pool_get(&unode_pool, PR_WAITOK0x0001 | PR_ZERO0x0008); |
578 | |
579 | /* |
580 | * Copy in the file entry. Per the spec, the size can only be 1 block. |
581 | */ |
582 | sector = ino; |
583 | devvp = ump->um_devvp; |
584 | udf_vat_map(ump, §or); |
585 | if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)bread(devvp, ((daddr_t)(sector) << ump->um_bshift) / (1 << 9), ump->um_bsize, &bp)) != 0) { |
586 | printf("Cannot read sector %d\n", sector); |
587 | pool_put(&unode_pool, up); |
588 | if (bp != NULL((void *)0)) |
589 | brelse(bp); |
590 | return (error); |
591 | } |
592 | |
593 | xfe = (struct extfile_entry *)bp->b_data; |
594 | fe = (struct file_entry *)bp->b_data; |
595 | error = udf_checktag(&xfe->tag, TAGID_EXTFENTRY); |
596 | if (error == 0) { |
597 | size = letoh32(xfe->l_ea)((__uint32_t)(xfe->l_ea)) + letoh32(xfe->l_ad)((__uint32_t)(xfe->l_ad)); |
598 | } else { |
599 | error = udf_checktag(&fe->tag, TAGID_FENTRY); |
600 | if (error) { |
601 | printf("Invalid file entry!\n"); |
602 | pool_put(&unode_pool, up); |
603 | if (bp != NULL((void *)0)) |
604 | brelse(bp); |
605 | return (ENOMEM12); |
606 | } else |
607 | size = letoh32(fe->l_ea)((__uint32_t)(fe->l_ea)) + letoh32(fe->l_ad)((__uint32_t)(fe->l_ad)); |
608 | } |
609 | |
610 | /* Allocate max size of FE/XFE. */ |
611 | up->u_fentry = malloc(size + UDF_EXTFENTRY_SIZE216, M_UDFFENTRY141, M_NOWAIT0x0002 | M_ZERO0x0008); |
612 | if (up->u_fentry == NULL((void *)0)) { |
613 | pool_put(&unode_pool, up); |
614 | if (bp != NULL((void *)0)) |
615 | brelse(bp); |
616 | return (ENOMEM12); /* Cannot allocate file entry block */ |
617 | } |
618 | |
619 | if (udf_checktag(&xfe->tag, TAGID_EXTFENTRY) == 0) |
620 | bcopy(bp->b_data, up->u_fentry, size + UDF_EXTFENTRY_SIZE216); |
621 | else |
622 | bcopy(bp->b_data, up->u_fentry, size + UDF_FENTRY_SIZE176); |
623 | |
624 | brelse(bp); |
625 | bp = NULL((void *)0); |
626 | |
627 | if ((error = udf_allocv(mp, &vp, p))) { |
628 | free(up->u_fentry, M_UDFFENTRY141, 0); |
629 | pool_put(&unode_pool, up); |
630 | return (error); /* Error from udf_allocv() */ |
631 | } |
632 | |
633 | up->u_vnode = vp; |
634 | up->u_ino = ino; |
635 | up->u_devvp = ump->um_devvp; |
636 | up->u_dev = ump->um_dev; |
637 | up->u_ump = ump; |
638 | vp->v_data = up; |
639 | vref(ump->um_devvp); |
640 | |
641 | rrw_init_flags(&up->u_lock, "unode", RWL_DUPOK | RWL_IS_VNODE)_rrw_init_flags(&up->u_lock, "unode", 0, ((void *)0)); |
642 | |
643 | /* |
644 | * udf_hashins() will lock the vnode for us. |
645 | */ |
646 | udf_hashins(up); |
647 | |
648 | switch (up->u_fentry->icbtag.file_type) { |
649 | default: |
650 | printf("Unrecognized file type (%d)\n", vp->v_type); |
651 | vp->v_type = VREG; |
652 | break; |
653 | case UDF_ICB_FILETYPE_DIRECTORY4: |
654 | vp->v_type = VDIR; |
655 | break; |
656 | case UDF_ICB_FILETYPE_BLOCKDEVICE6: |
657 | vp->v_type = VBLK; |
658 | break; |
659 | case UDF_ICB_FILETYPE_CHARDEVICE7: |
660 | vp->v_type = VCHR; |
661 | break; |
662 | case UDF_ICB_FILETYPE_FIFO9: |
663 | vp->v_type = VFIFO; |
664 | break; |
665 | case UDF_ICB_FILETYPE_SOCKET10: |
666 | vp->v_type = VSOCK; |
667 | break; |
668 | case UDF_ICB_FILETYPE_SYMLINK12: |
669 | vp->v_type = VLNK; |
670 | break; |
671 | case UDF_ICB_FILETYPE_RANDOMACCESS5: |
672 | case UDF_ICB_FILETYPE_REALTIME249: |
673 | case UDF_ICB_FILETYPE_UNKNOWN0: |
674 | vp->v_type = VREG; |
675 | break; |
676 | } |
677 | |
678 | /* check if this is a vnode alias */ |
679 | if ((nvp = checkalias(vp, up->u_dev, ump->um_mountp)) != NULL((void *)0)) { |
680 | printf("found a vnode alias\n"); |
681 | /* |
682 | * Discard unneeded vnode, but save its udf_node. |
683 | * Note that the lock is carried over in the udf_node |
684 | */ |
685 | nvp->v_data = vp->v_data; |
686 | vp->v_data = NULL((void *)0); |
687 | vp->v_op = &spec_vops; |
688 | vrele(vp); |
689 | vgone(vp); |
690 | /* |
691 | * Reinitialize aliased inode. |
692 | */ |
693 | vp = nvp; |
694 | ump->um_devvp = vp; |
695 | } |
696 | |
697 | *vpp = vp; |
698 | |
699 | return (0); |
700 | } |
701 | |
702 | struct ifid { |
703 | u_short ifid_len; |
704 | u_short ifid_pad; |
705 | int ifid_ino; |
706 | long ifid_start; |
707 | }; |
708 | |
709 | int |
710 | udf_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) |
711 | { |
712 | struct ifid *ifhp; |
713 | struct vnode *nvp; |
714 | int error; |
715 | |
716 | ifhp = (struct ifid *)fhp; |
717 | |
718 | if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)(*(mp)->mnt_op->vfs_vget)(mp, ifhp->ifid_ino, &nvp )) != 0) { |
719 | *vpp = NULLVP((struct vnode *)((void *)0)); |
720 | return (error); |
721 | } |
722 | |
723 | *vpp = nvp; |
724 | |
725 | return (0); |
726 | } |
727 | |
728 | int |
729 | udf_vptofh(struct vnode *vp, struct fid *fhp) |
730 | { |
731 | struct unode *up; |
732 | struct ifid *ifhp; |
733 | |
734 | up = VTOU(vp)((struct unode *)((vp)->v_data)); |
735 | ifhp = (struct ifid *)fhp; |
736 | ifhp->ifid_len = sizeof(struct ifid); |
737 | ifhp->ifid_ino = up->u_ino; |
738 | |
739 | return (0); |
740 | } |
741 | |
742 | int |
743 | udf_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, |
744 | size_t newlen, struct proc *p) |
745 | { |
746 | return (EINVAL22); |
747 | } |
748 | |
749 | int |
750 | udf_checkexp(struct mount *mp, struct mbuf *nam, int *exflagsp, |
751 | struct ucred **credanonp) |
752 | { |
753 | return (EACCES13); /* For the time being */ |
754 | } |
755 | |
756 | /* Handle a virtual partition map */ |
757 | int |
758 | udf_get_vpartmap(struct umount *ump, struct part_map_virt *pmv) |
759 | { |
760 | ump->um_flags |= UDF_MNT_FIND_VAT0x01; /* Should do more than this */ |
761 | return (0); |
762 | } |
763 | |
764 | /* Handle a sparable partition map */ |
765 | int |
766 | udf_get_spartmap(struct umount *ump, struct part_map_spare *pms) |
767 | { |
768 | struct buf *bp; |
769 | int i, error; |
770 | |
771 | ump->um_stbl = malloc(letoh32(pms->st_size)((__uint32_t)(pms->st_size)), M_UDFMOUNT140, M_NOWAIT0x0002); |
772 | if (ump->um_stbl == NULL((void *)0)) |
773 | return (ENOMEM12); |
774 | |
775 | bzero(ump->um_stbl, letoh32(pms->st_size))__builtin_bzero((ump->um_stbl), (((__uint32_t)(pms->st_size )))); |
776 | |
777 | /* Calculate the number of sectors per packet */ |
778 | ump->um_psecs = letoh16(pms->packet_len)((__uint16_t)(pms->packet_len)) / ump->um_bsize; |
779 | |
780 | error = udf_readlblks(ump, letoh32(pms->st_loc[0])((__uint32_t)(pms->st_loc[0])), |
781 | letoh32(pms->st_size)((__uint32_t)(pms->st_size)), &bp); |
782 | |
783 | if (error) { |
784 | if (bp != NULL((void *)0)) |
785 | brelse(bp); |
786 | free(ump->um_stbl, M_UDFMOUNT140, 0); |
787 | return (error); /* Failed to read sparing table */ |
788 | } |
789 | |
790 | bcopy(bp->b_data, ump->um_stbl, letoh32(pms->st_size)((__uint32_t)(pms->st_size))); |
791 | brelse(bp); |
792 | bp = NULL((void *)0); |
793 | |
794 | if (udf_checktag(&ump->um_stbl->tag, 0)) { |
795 | free(ump->um_stbl, M_UDFMOUNT140, 0); |
796 | return (EINVAL22); /* Invalid sparing table found */ |
797 | } |
798 | |
799 | /* |
800 | * See how many valid entries there are here. The list is |
801 | * supposed to be sorted, 0xfffffff0 and higher are not valid. |
802 | */ |
803 | for (i = 0; i < letoh16(ump->um_stbl->rt_l)((__uint16_t)(ump->um_stbl->rt_l)); i++) { |
804 | ump->um_stbl_len = i; |
805 | if (letoh32(ump->um_stbl->entries[i].org)((__uint32_t)(ump->um_stbl->entries[i].org)) >= 0xfffffff0) |
806 | break; |
807 | } |
808 | |
809 | return (0); |
810 | } |
811 | |
812 | /* Handle a metadata partition map */ |
813 | int |
814 | udf_get_mpartmap(struct umount *ump, struct part_map_meta *pmm) |
815 | { |
816 | ump->um_flags |= UDF_MNT_USES_META0x04; |
817 | ump->um_meta_start = pmm->meta_file_lbn; |
818 | return (0); |
819 | } |
820 | |
821 | /* Scan the partition maps */ |
822 | int |
823 | udf_find_partmaps(struct umount *ump, struct logvol_desc *lvd) |
824 | { |
825 | struct regid *pmap_id; |
826 | unsigned char regid_id[UDF_REGID_ID_SIZE23 + 1]; |
827 | int i, ptype, psize, error; |
828 | uint8_t *pmap = (uint8_t *) &lvd->maps[0]; |
829 | |
830 | for (i = 0; i < letoh32(lvd->n_pm)((__uint32_t)(lvd->n_pm)); i++) { |
831 | ptype = pmap[0]; |
832 | psize = pmap[1]; |
833 | |
834 | if (ptype != 1 && ptype != 2) |
835 | return (EINVAL22); /* Invalid partition map type */ |
836 | |
837 | if (psize != sizeof(struct part_map_1) && |
838 | psize != sizeof(struct part_map_2)) |
839 | return (EINVAL22); /* Invalid partition map size */ |
840 | |
841 | if (ptype == 1) { |
842 | pmap += sizeof(struct part_map_1); |
843 | continue; |
844 | } |
845 | |
846 | /* Type 2 map. Find out the details */ |
847 | pmap_id = (struct regid *) &pmap[4]; |
848 | regid_id[UDF_REGID_ID_SIZE23] = '\0'; |
849 | bcopy(&pmap_id->id[0], ®id_id[0], UDF_REGID_ID_SIZE23); |
850 | |
851 | if (!bcmp(®id_id[0], "*UDF Virtual Partition", |
852 | UDF_REGID_ID_SIZE23)) |
853 | error = udf_get_vpartmap(ump, |
854 | (struct part_map_virt *) pmap); |
855 | else if (!bcmp(®id_id[0], "*UDF Sparable Partition", |
856 | UDF_REGID_ID_SIZE23)) |
857 | error = udf_get_spartmap(ump, |
858 | (struct part_map_spare *) pmap); |
859 | else if (!bcmp(®id_id[0], "*UDF Metadata Partition", |
860 | UDF_REGID_ID_SIZE23)) |
861 | error = udf_get_mpartmap(ump, |
862 | (struct part_map_meta *) pmap); |
863 | else |
864 | return (EINVAL22); /* Unsupported partition map */ |
865 | |
866 | if (error) |
867 | return (error); /* Error getting partition */ |
868 | |
869 | pmap += sizeof(struct part_map_2); |
870 | } |
871 | |
872 | return (0); |
873 | } |