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