xref: /openbsd-src/sys/isofs/udf/udf_vfsops.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: udf_vfsops.c,v 1.27 2008/06/14 10:55:21 mk 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 demostrates 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/types.h>
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/uio.h>
53 #include <sys/buf.h>
54 #include <sys/conf.h>
55 #include <sys/dirent.h>
56 #include <sys/fcntl.h>
57 #include <sys/kernel.h>
58 #include <sys/malloc.h>
59 #include <sys/mutex.h>
60 #include <sys/mount.h>
61 #include <sys/namei.h>
62 #include <sys/pool.h>
63 #include <sys/proc.h>
64 #include <sys/lock.h>
65 #include <sys/queue.h>
66 #include <sys/vnode.h>
67 #include <sys/endian.h>
68 
69 #include <miscfs/specfs/specdev.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_mountfs(struct vnode *, struct mount *, uint32_t, struct proc *);
83 
84 const struct vfsops udf_vfsops = {
85 	.vfs_fhtovp =		udf_fhtovp,
86 	.vfs_init =		udf_init,
87 	.vfs_mount =		udf_mount,
88 	.vfs_start =		udf_start,
89 	.vfs_root =		udf_root,
90 	.vfs_quotactl =		udf_quotactl,
91 	.vfs_statfs =		udf_statfs,
92 	.vfs_sync =		udf_sync,
93 	.vfs_unmount =		udf_unmount,
94 	.vfs_vget =		udf_vget,
95 	.vfs_vptofh =		udf_vptofh,
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, MAXNAMLEN * sizeof(unicode_t), 0, 0, 0,
104 	    "udftrpl", &pool_allocator_nointr);
105 	pool_init(&unode_pool, sizeof(struct unode), 0, 0, 0,
106 	    "udfndpl", &pool_allocator_nointr);
107 	pool_init(&udf_ds_pool, sizeof(struct udf_dirstream), 0, 0, 0,
108 	    "udfdspl", &pool_allocator_nointr);
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;
125 	size_t len;
126 	int error;
127 
128 	if ((mp->mnt_flag & MNT_RDONLY) == 0) {
129 		mp->mnt_flag |= MNT_RDONLY;
130 		printf("udf_mount: enforcing read-only mode\n");
131 	}
132 
133 	/*
134 	 * No root filesystem support.  Probably not a big deal, since the
135 	 * bootloader doesn't understand UDF.
136 	 */
137 	if (mp->mnt_flag & MNT_ROOTFS)
138 		return (EOPNOTSUPP);
139 
140 	error = copyin(data, &args, sizeof(struct udf_args));
141 	if (error)
142 		return (error);
143 
144 	if (args.fspec == NULL)
145 		return (EINVAL);
146 
147 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
148 	if ((error = namei(ndp)))
149 		return (error);
150 
151 	devvp = ndp->ni_vp;
152 	if (devvp->v_type != VBLK) {
153 		vrele(devvp);
154 		return (ENOTBLK);
155 	}
156 
157 	if (major(devvp->v_rdev) >= nblkdev) {
158 		vrele(devvp);
159 		return (ENXIO);
160 	}
161 
162 	/* Check the access rights on the mount device */
163 	if (p->p_ucred->cr_uid) {
164 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
165 		error = VOP_ACCESS(devvp, VREAD, p->p_ucred, p);
166 		VOP_UNLOCK(devvp, 0, p);
167 		if (error) {
168 			vrele(devvp);
169 			return (error);
170 		}
171 	}
172 
173 	if ((error = udf_mountfs(devvp, mp, args.lastblock, p))) {
174 		vrele(devvp);
175 		return (error);
176 	}
177 
178 	/*
179 	 * Keep a copy of the mount information.
180 	 */
181 	copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &len);
182 	bzero(mp->mnt_stat.f_mntonname + len, MNAMELEN - len);
183 	copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &len);
184 	bzero(mp->mnt_stat.f_mntfromname + len, MNAMELEN - len);
185 
186 	return (0);
187 };
188 
189 /*
190  * Check the descriptor tag for both the correct id and correct checksum.
191  * Return zero if all is good, EINVAL if not.
192  */
193 int
194 udf_checktag(struct desc_tag *tag, uint16_t id)
195 {
196 	uint8_t *itag;
197 	uint8_t i, cksum = 0;
198 
199 	itag = (uint8_t *)tag;
200 
201 	if (letoh16(tag->id) != id)
202 		return (EINVAL);
203 
204 	for (i = 0; i < 15; i++)
205 		cksum = cksum + itag[i];
206 	cksum = cksum - itag[4];
207 
208 	if (cksum == tag->cksum)
209 		return (0);
210 
211 	return (EINVAL);
212 }
213 
214 int
215 udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p)
216 {
217 	struct buf *bp = NULL;
218 	struct anchor_vdp avdp;
219 	struct umount *ump = NULL;
220 	struct part_desc *pd;
221 	struct logvol_desc *lvd;
222 	struct fileset_desc *fsd;
223 	struct file_entry *root_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 = EINVAL;
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 (EBUSY);
241 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
242 	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
243 	VOP_UNLOCK(devvp, 0, p);
244 	if (error)
245 		return (error);
246 
247 	error = VOP_OPEN(devvp, FREAD, FSCRED, p);
248 	if (error)
249 		return (error);
250 
251 	ump = malloc(sizeof(*ump), M_UDFMOUNT, M_WAITOK | M_ZERO);
252 
253 	mp->mnt_data = (qaddr_t) ump;
254 	mp->mnt_stat.f_fsid.val[0] = devvp->v_rdev;
255 	mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_UDF);
256 	mp->mnt_flag |= MNT_LOCAL;
257 
258 	ump->um_mountp = mp;
259 	ump->um_dev = devvp->v_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, NOCRED,
270 			   &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;
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);
286 	mvds_end = mvds_start + (letoh32(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,
289 				   NOCRED, &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);
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);
299 			fsd_offset = letoh32(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);
308 			ump->um_len = letoh32(pd->part_len);
309 			ump->um_start = letoh32(pd->start_loc);
310 		}
311 
312 		brelse(bp);
313 		bp = NULL;
314 		if ((part_found) && (logvol_found))
315 			break;
316 	}
317 
318 	if (!part_found || !logvol_found) {
319 		error = EINVAL;
320 		goto bail;
321 	}
322 
323 	if (fsd_part != part_num) {
324 		printf("FSD does not lie within the partition!\n");
325 		error = EINVAL;
326 		goto bail;
327 	}
328 
329 	mtx_init(&ump->um_hashmtx, IPL_NONE);
330 	ump->um_hashtbl = hashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, M_WAITOK,
331 	    &ump->um_hashsz);
332 
333 	/* Get the VAT, if needed */
334 	if (ump->um_flags & UDF_MNT_FIND_VAT) {
335 		error = udf_vat_get(ump, lb);
336 		if (error)
337 			goto bail;
338 	}
339 
340 	/*
341 	 * Grab the Fileset Descriptor
342 	 * Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing
343 	 * me in the right direction here.
344 	 */
345 	sector = fsd_offset;
346 	udf_vat_map(ump, &sector);
347 	if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
348 		printf("Cannot read sector %d of FSD\n", sector);
349 		goto bail;
350 	}
351 	fsd = (struct fileset_desc *)bp->b_data;
352 	if (!udf_checktag(&fsd->tag, TAGID_FSD)) {
353 		fsd_found = 1;
354 		bcopy(&fsd->rootdir_icb, &ump->um_root_icb,
355 		    sizeof(struct long_ad));
356 	}
357 
358 	brelse(bp);
359 	bp = NULL;
360 
361 	if (!fsd_found) {
362 		printf("Couldn't find the fsd\n");
363 		error = EINVAL;
364 		goto bail;
365 	}
366 
367 	/*
368 	 * Find the file entry for the root directory.
369 	 */
370 	sector = letoh32(ump->um_root_icb.loc.lb_num);
371 	size = letoh32(ump->um_root_icb.len);
372 	udf_vat_map(ump, &sector);
373 	if ((error = udf_readlblks(ump, sector, size, &bp)) != 0) {
374 		printf("Cannot read sector %d\n", sector);
375 		goto bail;
376 	}
377 
378 	root_fentry = (struct file_entry *)bp->b_data;
379 	if ((error = udf_checktag(&root_fentry->tag, TAGID_FENTRY))) {
380 		printf("Invalid root file entry!\n");
381 		goto bail;
382 	}
383 
384 	brelse(bp);
385 	bp = NULL;
386 
387 	devvp->v_specmountpoint = mp;
388 
389 	return (0);
390 
391 bail:
392 	if (ump->um_hashtbl != NULL)
393 		free(ump->um_hashtbl, M_UDFMOUNT);
394 
395 	if (ump != NULL) {
396 		free(ump, M_UDFMOUNT);
397 		mp->mnt_data = NULL;
398 		mp->mnt_flag &= ~MNT_LOCAL;
399 	}
400 	if (bp != NULL)
401 		brelse(bp);
402 	VOP_CLOSE(devvp, FREAD, FSCRED, p);
403 
404 	return (error);
405 }
406 
407 int
408 udf_unmount(struct mount *mp, int mntflags, struct proc *p)
409 {
410 	struct umount *ump;
411 	struct vnode *devvp;
412 	int error, flags = 0;
413 
414 	ump = VFSTOUDFFS(mp);
415 	devvp = ump->um_devvp;
416 
417 	if (mntflags & MNT_FORCE)
418 		flags |= FORCECLOSE;
419 
420 	if ((error = vflush(mp, NULL, flags)))
421 		return (error);
422 
423 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
424 	vinvalbuf(devvp, V_SAVE, NOCRED, p, 0, 0);
425 	error = VOP_CLOSE(devvp, FREAD, NOCRED, p);
426 	VOP_UNLOCK(devvp, 0, p);
427 	if (error)
428 		return (error);
429 
430 	devvp->v_specmountpoint = NULL;
431 	vrele(devvp);
432 
433 	if (ump->um_flags & UDF_MNT_USES_VAT)
434 		free(ump->um_vat, M_UDFMOUNT);
435 
436 	if (ump->um_stbl != NULL)
437 		free(ump->um_stbl, M_UDFMOUNT);
438 
439 	if (ump->um_hashtbl != NULL)
440 		free(ump->um_hashtbl, M_UDFMOUNT);
441 
442 	free(ump, M_UDFMOUNT);
443 
444 	mp->mnt_data = (qaddr_t)0;
445 	mp->mnt_flag &= ~MNT_LOCAL;
446 
447 	return (0);
448 }
449 
450 int
451 udf_root(struct mount *mp, struct vnode **vpp)
452 {
453 	struct umount *ump;
454 	struct vnode *vp;
455 	ino_t id;
456 	int error;
457 
458 	ump = VFSTOUDFFS(mp);
459 
460 	id = udf_getid(&ump->um_root_icb);
461 
462 	error = udf_vget(mp, id, vpp);
463 	if (error)
464 		return (error);
465 
466 	vp = *vpp;
467 	vp->v_flag |= VROOT;
468 
469 	return (0);
470 }
471 
472 int
473 udf_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
474     struct proc *p)
475 {
476 	return (EOPNOTSUPP);
477 }
478 
479 int
480 udf_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
481 {
482 	struct umount *ump;
483 
484 	ump = VFSTOUDFFS(mp);
485 
486 	sbp->f_bsize = ump->um_bsize;
487 	sbp->f_iosize = ump->um_bsize;
488 	sbp->f_blocks = ump->um_len;
489 	sbp->f_bfree = 0;
490 	sbp->f_bavail = 0;
491 	sbp->f_files = 0;
492 	sbp->f_ffree = 0;
493 
494 	return (0);
495 }
496 
497 int
498 udf_sync(struct mount *mp, int waitfor, struct ucred *cred, struct proc *p)
499 {
500 	return (0);
501 }
502 
503 int
504 udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
505 {
506 	struct buf *bp;
507 	struct vnode *devvp;
508 	struct umount *ump;
509 	struct proc *p;
510 	struct vnode *vp;
511 	struct unode *up;
512 	struct file_entry *fe;
513 	int error, sector, size;
514 
515 	p = curproc;
516 	bp = NULL;
517 	*vpp = NULL;
518 	ump = VFSTOUDFFS(mp);
519 
520 	/* See if we already have this in the cache */
521 	if ((error = udf_hashlookup(ump, ino, LK_EXCLUSIVE, vpp)) != 0)
522 		return (error);
523 	if (*vpp != NULL)
524 		return (0);
525 
526 	/*
527 	 * Allocate memory and check the tag id's before grabbing a new
528 	 * vnode, since it's hard to roll back if there is a problem.
529 	 */
530 	up = pool_get(&unode_pool, PR_WAITOK | PR_ZERO);
531 
532 	/*
533 	 * Copy in the file entry.  Per the spec, the size can only be 1 block.
534 	 */
535 	sector = ino;
536 	devvp = ump->um_devvp;
537 	udf_vat_map(ump, &sector);
538 	if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
539 		printf("Cannot read sector %d\n", sector);
540 		pool_put(&unode_pool, up);
541 		if (bp != NULL)
542 			brelse(bp);
543 		return (error);
544 	}
545 
546 	fe = (struct file_entry *)bp->b_data;
547 	if (udf_checktag(&fe->tag, TAGID_FENTRY)) {
548 		printf("Invalid file entry!\n");
549 		pool_put(&unode_pool, up);
550 		brelse(bp);
551 		return (ENOMEM);
552 	}
553 
554 	size = UDF_FENTRY_SIZE + letoh32(fe->l_ea) + letoh32(fe->l_ad);
555 
556 	up->u_fentry = malloc(size, M_UDFFENTRY, M_NOWAIT);
557 	if (up->u_fentry == NULL) {
558 		pool_put(&unode_pool, up);
559 		brelse(bp);
560 		return (ENOMEM); /* Cannot allocate file entry block */
561 	}
562 
563 	bcopy(bp->b_data, up->u_fentry, size);
564 
565 	brelse(bp);
566 	bp = NULL;
567 
568 	if ((error = udf_allocv(mp, &vp, p))) {
569 		free(up->u_fentry, M_UDFFENTRY);
570 		pool_put(&unode_pool, up);
571 		return (error); /* Error from udf_allocv() */
572 	}
573 
574 	up->u_vnode = vp;
575 	up->u_ino = ino;
576 	up->u_devvp = ump->um_devvp;
577 	up->u_dev = ump->um_dev;
578 	up->u_ump = ump;
579 	vp->v_data = up;
580 	VREF(ump->um_devvp);
581 
582 	lockinit(&up->u_lock, PINOD, "unode", 0, 0);
583 
584 	/*
585 	 * udf_hashins() will lock the vnode for us.
586 	 */
587 	udf_hashins(up);
588 
589 	switch (up->u_fentry->icbtag.file_type) {
590 	default:
591 		vp->v_type = VBAD;
592 		break;
593 	case UDF_ICB_TYPE_DIR:
594 		vp->v_type = VDIR;
595 		break;
596 	case UDF_ICB_TYPE_FILE:
597 		vp->v_type = VREG;
598 		break;
599 	case UDF_ICB_TYPE_BLKDEV:
600 		vp->v_type = VBLK;
601 		break;
602 	case UDF_ICB_TYPE_CHRDEV:
603 		vp->v_type = VCHR;
604 		break;
605 	case UDF_ICB_TYPE_FIFO:
606 		vp->v_type = VFIFO;
607 		break;
608 	case UDF_ICB_TYPE_SOCKET:
609 		vp->v_type = VSOCK;
610 		break;
611 	case UDF_ICB_TYPE_SYMLINK:
612 		vp->v_type = VLNK;
613 		break;
614 	case UDF_ICB_TYPE_VAT_150:
615 		vp->v_type = VREG;
616 		break;
617 	}
618 
619 	*vpp = vp;
620 
621 	return (0);
622 }
623 
624 struct ifid {
625 	u_short	ifid_len;
626 	u_short	ifid_pad;
627 	int	ifid_ino;
628 	long	ifid_start;
629 };
630 
631 int
632 udf_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
633 {
634 	struct ifid *ifhp;
635 	struct vnode *nvp;
636 	int error;
637 
638 	ifhp = (struct ifid *)fhp;
639 
640 	if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) {
641 		*vpp = NULLVP;
642 		return (error);
643 	}
644 
645 	*vpp = nvp;
646 
647 	return (0);
648 }
649 
650 int
651 udf_vptofh(struct vnode *vp, struct fid *fhp)
652 {
653 	struct unode *up;
654 	struct ifid *ifhp;
655 
656 	up = VTOU(vp);
657 	ifhp = (struct ifid *)fhp;
658 	ifhp->ifid_len = sizeof(struct ifid);
659 	ifhp->ifid_ino = up->u_ino;
660 
661 	return (0);
662 }
663 
664 int
665 udf_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
666     size_t newlen, struct proc *p)
667 {
668 	return (EINVAL);
669 }
670 
671 int
672 udf_checkexp(struct mount *mp, struct mbuf *nam, int *exflagsp,
673     struct ucred **credanonp)
674 {
675 	return (EACCES); /* For the time being */
676 }
677 
678 /* Handle a virtual partition map */
679 int
680 udf_get_vpartmap(struct umount *ump, struct part_map_virt *pmv)
681 {
682 	ump->um_flags |= UDF_MNT_FIND_VAT; /* Should do more than this */
683 	return (0);
684 }
685 
686 /* Handle a sparable partition map */
687 int
688 udf_get_spartmap(struct umount *ump, struct part_map_spare *pms)
689 {
690 	struct buf *bp;
691 	int i, error;
692 
693 	ump->um_stbl = malloc(letoh32(pms->st_size), M_UDFMOUNT, M_NOWAIT);
694 	if (ump->um_stbl == NULL)
695 		return (ENOMEM);
696 
697 	bzero(ump->um_stbl, letoh32(pms->st_size));
698 
699 	/* Calculate the number of sectors per packet */
700 	ump->um_psecs = letoh16(pms->packet_len) / ump->um_bsize;
701 
702 	error = udf_readlblks(ump, letoh32(pms->st_loc[0]),
703 	    letoh32(pms->st_size), &bp);
704 
705 	if (error) {
706 		if (bp != NULL)
707 			brelse(bp);
708 		free(ump->um_stbl, M_UDFMOUNT);
709 		return (error); /* Failed to read sparing table */
710 	}
711 
712 	bcopy(bp->b_data, ump->um_stbl, letoh32(pms->st_size));
713 	brelse(bp);
714 
715 	if (udf_checktag(&ump->um_stbl->tag, 0)) {
716 		free(ump->um_stbl, M_UDFMOUNT);
717 		return (EINVAL); /* Invalid sparing table found */
718 	}
719 
720 	/*
721 	 * See how many valid entries there are here. The list is
722 	 * supposed to be sorted, 0xfffffff0 and higher are not valid.
723 	 */
724 	for (i = 0; i < letoh16(ump->um_stbl->rt_l); i++) {
725 		ump->um_stbl_len = i;
726 		if (letoh32(ump->um_stbl->entries[i].org) >= 0xfffffff0)
727 			break;
728 	}
729 
730 	return (0);
731 }
732 
733 /* Scan the partition maps */
734 int
735 udf_find_partmaps(struct umount *ump, struct logvol_desc *lvd)
736 {
737 	struct regid *pmap_id;
738 	unsigned char regid_id[UDF_REGID_ID_SIZE + 1];
739 	int i, ptype, psize, error;
740 	uint8_t *pmap = (uint8_t *) &lvd->maps[0];
741 
742 	for (i = 0; i < letoh32(lvd->n_pm); i++) {
743 		ptype = pmap[0];
744 		psize = pmap[1];
745 
746 		if (ptype != 1 && ptype != 2)
747 			return (EINVAL); /* Invalid partition map type */
748 
749 		if (psize != UDF_PMAP_TYPE1_SIZE &&
750 		    psize != UDF_PMAP_TYPE2_SIZE)
751 			return (EINVAL); /* Invalid partition map size */
752 
753 		if (ptype == 1) {
754 			pmap += UDF_PMAP_TYPE1_SIZE;
755 			continue;
756 		}
757 
758 		/* Type 2 map. Find out the details */
759 		pmap_id = (struct regid *) &pmap[4];
760 		regid_id[UDF_REGID_ID_SIZE] = '\0';
761 		bcopy(&pmap_id->id[0], &regid_id[0], UDF_REGID_ID_SIZE);
762 
763 		if (!bcmp(&regid_id[0], "*UDF Virtual Partition",
764 		    UDF_REGID_ID_SIZE))
765 			error = udf_get_vpartmap(ump,
766 			    (struct part_map_virt *) pmap);
767 		else if (!bcmp(&regid_id[0], "*UDF Sparable Partition",
768 		    UDF_REGID_ID_SIZE))
769 			error = udf_get_spartmap(ump,
770 			    (struct part_map_spare *) pmap);
771 		else
772 			return (EINVAL); /* Unsupported partition map */
773 
774 		if (error)
775 			return (error); /* Error getting partition */
776 
777 		pmap += UDF_PMAP_TYPE2_SIZE;
778 	}
779 
780 	return (0);
781 }
782