xref: /freebsd/sys/fs/udf/udf_vfsops.c (revision 822923447e454b30d310cb46903c9ddeca9f0a7a)
1 /*-
2  * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 /* udf_vfsops.c */
30 /* Implement the VFS side of things */
31 
32 /*
33  * Ok, here's how it goes.  The UDF specs are pretty clear on how each data
34  * structure is made up, but not very clear on how they relate to each other.
35  * Here is the skinny... This demostrates a filesystem with one file in the
36  * root directory.  Subdirectories are treated just as normal files, but they
37  * have File Id Descriptors of their children as their file data.  As for the
38  * Anchor Volume Descriptor Pointer, it can exist in two of the following three
39  * places: sector 256, sector n (the max sector of the disk), or sector
40  * n - 256.  It's a pretty good bet that one will exist at sector 256 though.
41  * One caveat is unclosed CD media.  For that, sector 256 cannot be written,
42  * so the Anchor Volume Descriptor Pointer can exist at sector 512 until the
43  * media is closed.
44  *
45  *  Sector:
46  *     256:
47  *       n: Anchor Volume Descriptor Pointer
48  * n - 256:	|
49  *		|
50  *		|-->Main Volume Descriptor Sequence
51  *			|	|
52  *			|	|
53  *			|	|-->Logical Volume Descriptor
54  *			|			  |
55  *			|-->Partition Descriptor  |
56  *				|		  |
57  *				|		  |
58  *				|-->Fileset Descriptor
59  *					|
60  *					|
61  *					|-->Root Dir File Entry
62  *						|
63  *						|
64  *						|-->File data:
65  *						    File Id Descriptor
66  *							|
67  *							|
68  *							|-->File Entry
69  *								|
70  *								|
71  *								|-->File data
72  */
73 #include <sys/types.h>
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/uio.h>
77 #include <sys/bio.h>
78 #include <sys/buf.h>
79 #include <sys/conf.h>
80 #include <sys/dirent.h>
81 #include <sys/fcntl.h>
82 #include <sys/iconv.h>
83 #include <sys/kernel.h>
84 #include <sys/malloc.h>
85 #include <sys/mount.h>
86 #include <sys/namei.h>
87 #include <sys/proc.h>
88 #include <sys/queue.h>
89 #include <sys/vnode.h>
90 #include <sys/endian.h>
91 
92 #include <geom/geom.h>
93 #include <geom/geom_vfs.h>
94 
95 #include <vm/uma.h>
96 
97 #include <fs/udf/ecma167-udf.h>
98 #include <fs/udf/osta.h>
99 #include <fs/udf/udf.h>
100 #include <fs/udf/udf_mount.h>
101 
102 static MALLOC_DEFINE(M_UDFMOUNT, "UDF mount", "UDF mount structure");
103 MALLOC_DEFINE(M_UDFFENTRY, "UDF fentry", "UDF file entry structure");
104 
105 struct iconv_functions *udf_iconv = NULL;
106 
107 /* Zones */
108 uma_zone_t udf_zone_trans = NULL;
109 uma_zone_t udf_zone_node = NULL;
110 uma_zone_t udf_zone_ds = NULL;
111 
112 static vfs_init_t      udf_init;
113 static vfs_uninit_t    udf_uninit;
114 static vfs_mount_t     udf_mount;
115 static vfs_root_t      udf_root;
116 static vfs_statfs_t    udf_statfs;
117 static vfs_unmount_t   udf_unmount;
118 static vfs_fhtovp_t	udf_fhtovp;
119 static vfs_vptofh_t	udf_vptofh;
120 
121 static int udf_find_partmaps(struct udf_mnt *, struct logvol_desc *);
122 
123 static struct vfsops udf_vfsops = {
124 	.vfs_fhtovp =		udf_fhtovp,
125 	.vfs_init =		udf_init,
126 	.vfs_mount =		udf_mount,
127 	.vfs_root =		udf_root,
128 	.vfs_statfs =		udf_statfs,
129 	.vfs_uninit =		udf_uninit,
130 	.vfs_unmount =		udf_unmount,
131 	.vfs_vget =		udf_vget,
132 	.vfs_vptofh =		udf_vptofh,
133 };
134 VFS_SET(udf_vfsops, udf, VFCF_READONLY);
135 
136 MODULE_VERSION(udf, 1);
137 
138 static int udf_mountfs(struct vnode *, struct mount *, struct thread *);
139 
140 static int
141 udf_init(struct vfsconf *foo)
142 {
143 
144 	/*
145 	 * This code used to pre-allocate a certain number of pages for each
146 	 * pool, reducing the need to grow the zones later on.  UMA doesn't
147 	 * advertise any such functionality, unfortunately =-<
148 	 */
149 	udf_zone_trans = uma_zcreate("UDF translation buffer, zone", MAXNAMLEN *
150 	    sizeof(unicode_t), NULL, NULL, NULL, NULL, 0, 0);
151 
152 	udf_zone_node = uma_zcreate("UDF Node zone", sizeof(struct udf_node),
153 	    NULL, NULL, NULL, NULL, 0, 0);
154 
155 	udf_zone_ds = uma_zcreate("UDF Dirstream zone",
156 	    sizeof(struct udf_dirstream), NULL, NULL, NULL, NULL, 0, 0);
157 
158 	if ((udf_zone_node == NULL) || (udf_zone_trans == NULL) ||
159 	    (udf_zone_ds == NULL)) {
160 		printf("Cannot create allocation zones.\n");
161 		return (ENOMEM);
162 	}
163 
164 	return 0;
165 }
166 
167 static int
168 udf_uninit(struct vfsconf *foo)
169 {
170 
171 	if (udf_zone_trans != NULL) {
172 		uma_zdestroy(udf_zone_trans);
173 		udf_zone_trans = NULL;
174 	}
175 
176 	if (udf_zone_node != NULL) {
177 		uma_zdestroy(udf_zone_node);
178 		udf_zone_node = NULL;
179 	}
180 
181 	if (udf_zone_ds != NULL) {
182 		uma_zdestroy(udf_zone_ds);
183 		udf_zone_ds = NULL;
184 	}
185 
186 	return (0);
187 }
188 
189 static int
190 udf_mount(struct mount *mp, struct thread *td)
191 {
192 	struct vnode *devvp;	/* vnode of the mount device */
193 	struct udf_mnt *imp = 0;
194 	struct export_args *export;
195 	struct vfsoptlist *opts;
196 	char *fspec, *cs_disk, *cs_local;
197 	int error, len, *udf_flags;
198 	struct nameidata nd, *ndp = &nd;
199 
200 	opts = mp->mnt_optnew;
201 
202 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
203 		return (EROFS);
204 
205 	/*
206 	 * No root filesystem support.  Probably not a big deal, since the
207 	 * bootloader doesn't understand UDF.
208 	 */
209 	if (mp->mnt_flag & MNT_ROOTFS)
210 		return (ENOTSUP);
211 
212 	fspec = NULL;
213 	error = vfs_getopt(opts, "from", (void **)&fspec, &len);
214 	if (!error && fspec[len - 1] != '\0')
215 		return (EINVAL);
216 
217 	if (mp->mnt_flag & MNT_UPDATE) {
218 		if (fspec == NULL) {
219 			error = vfs_getopt(opts, "export", (void **)&export,
220 			    &len);
221 			if (error || len != sizeof(struct export_args))
222 				return (EINVAL);
223 			return (vfs_export(mp, export));
224 		}
225 	}
226 
227 	/* Check that the mount device exists */
228 	if (fspec == NULL)
229 		return (EINVAL);
230 	NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td);
231 	if ((error = namei(ndp)))
232 		return (error);
233 	NDFREE(ndp, NDF_ONLY_PNBUF);
234 	devvp = ndp->ni_vp;
235 
236 	if (vn_isdisk(devvp, &error) == 0) {
237 		vput(devvp);
238 		return (error);
239 	}
240 
241 	/* Check the access rights on the mount device */
242 	error = VOP_ACCESS(devvp, VREAD, td->td_ucred, td);
243 	if (error)
244 		error = suser(td);
245 	if (error) {
246 		vput(devvp);
247 		return (error);
248 	}
249 
250 	if ((error = udf_mountfs(devvp, mp, td))) {
251 		vrele(devvp);
252 		return (error);
253 	}
254 
255 	imp = VFSTOUDFFS(mp);
256 
257 	udf_flags = NULL;
258 	error = vfs_getopt(opts, "flags", (void **)&udf_flags, &len);
259 	if (error || len != sizeof(int))
260 		return (EINVAL);
261 	imp->im_flags = *udf_flags;
262 
263 	if (imp->im_flags & UDFMNT_KICONV && udf_iconv) {
264 		cs_disk = NULL;
265 		error = vfs_getopt(opts, "cs_disk", (void **)&cs_disk, &len);
266 		if (!error && cs_disk[len - 1] != '\0')
267 			return (EINVAL);
268 		cs_local = NULL;
269 		error = vfs_getopt(opts, "cs_local", (void **)&cs_local, &len);
270 		if (!error && cs_local[len - 1] != '\0')
271 			return (EINVAL);
272 		udf_iconv->open(cs_local, cs_disk, &imp->im_d2l);
273 #if 0
274 		udf_iconv->open(cs_disk, cs_local, &imp->im_l2d);
275 #endif
276 	}
277 
278 	vfs_mountedfrom(mp, fspec);
279 	return 0;
280 };
281 
282 /*
283  * Check the descriptor tag for both the correct id and correct checksum.
284  * Return zero if all is good, EINVAL if not.
285  */
286 int
287 udf_checktag(struct desc_tag *tag, uint16_t id)
288 {
289 	uint8_t *itag;
290 	uint8_t i, cksum = 0;
291 
292 	itag = (uint8_t *)tag;
293 
294 	if (tag->id != id)
295 		return (EINVAL);
296 
297 	for (i = 0; i < 15; i++)
298 		cksum = cksum + itag[i];
299 	cksum = cksum - itag[4];
300 
301 	if (cksum == tag->cksum)
302 		return (0);
303 
304 	return (EINVAL);
305 }
306 
307 static int
308 udf_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td) {
309 	struct buf *bp = NULL;
310 	struct anchor_vdp avdp;
311 	struct udf_mnt *udfmp = NULL;
312 	struct part_desc *pd;
313 	struct logvol_desc *lvd;
314 	struct fileset_desc *fsd;
315 	struct file_entry *root_fentry;
316 	uint32_t sector, size, mvds_start, mvds_end;
317 	uint32_t logical_secsize;
318 	uint32_t fsd_offset = 0;
319 	uint16_t part_num = 0, fsd_part = 0;
320 	int error = EINVAL;
321 	int logvol_found = 0, part_found = 0, fsd_found = 0;
322 	int bsize;
323 	struct g_consumer *cp;
324 	struct bufobj *bo;
325 
326 	DROP_GIANT();
327 	g_topology_lock();
328 	error = g_vfs_open(devvp, &cp, "udf", 0);
329 	g_topology_unlock();
330 	PICKUP_GIANT();
331 	VOP_UNLOCK(devvp, 0, td);
332 	if (error)
333 		return error;
334 
335 	bo = &devvp->v_bufobj;
336 
337 	/* XXX: should be M_WAITOK */
338 	MALLOC(udfmp, struct udf_mnt *, sizeof(struct udf_mnt), M_UDFMOUNT,
339 	    M_NOWAIT | M_ZERO);
340 	if (udfmp == NULL) {
341 		printf("Cannot allocate UDF mount struct\n");
342 		error = ENOMEM;
343 		goto bail;
344 	}
345 
346 	mp->mnt_data = (qaddr_t)udfmp;
347 	mp->mnt_stat.f_fsid.val[0] = dev2udev(devvp->v_rdev);
348 	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
349 	mp->mnt_flag |= MNT_LOCAL;
350 	udfmp->im_mountp = mp;
351 	udfmp->im_dev = devvp->v_rdev;
352 	udfmp->im_devvp = devvp;
353 	udfmp->im_d2l = NULL;
354 	udfmp->im_cp = cp;
355 	udfmp->im_bo = bo;
356 
357 #if 0
358 	udfmp->im_l2d = NULL;
359 #endif
360 	/*
361 	 * The UDF specification defines a logical sectorsize of 2048
362 	 * for DVD media.
363 	 */
364 	logical_secsize = 2048;
365 
366 	if (((logical_secsize % cp->provider->sectorsize) != 0) ||
367 	    (logical_secsize < cp->provider->sectorsize)) {
368 		DROP_GIANT();
369 		g_topology_lock();
370 		g_vfs_close(cp, td);
371 		g_topology_unlock();
372 		PICKUP_GIANT();
373 		return (EINVAL);
374 	}
375 
376 	bsize = cp->provider->sectorsize;
377 
378 	/*
379 	 * Get the Anchor Volume Descriptor Pointer from sector 256.
380 	 * XXX Should also check sector n - 256, n, and 512.
381 	 */
382 	sector = 256;
383 	if ((error = bread(devvp, sector * btodb(logical_secsize), bsize,
384 			   NOCRED, &bp)) != 0)
385 		goto bail;
386 	if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)))
387 		goto bail;
388 
389 	bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp));
390 	brelse(bp);
391 	bp = NULL;
392 
393 	/*
394 	 * Extract the Partition Descriptor and Logical Volume Descriptor
395 	 * from the Volume Descriptor Sequence.
396 	 * XXX Should we care about the partition type right now?
397 	 * XXX What about multiple partitions?
398 	 */
399 	mvds_start = le32toh(avdp.main_vds_ex.loc);
400 	mvds_end = mvds_start + (le32toh(avdp.main_vds_ex.len) - 1) / bsize;
401 	for (sector = mvds_start; sector < mvds_end; sector++) {
402 		if ((error = bread(devvp, sector * btodb(logical_secsize),
403 				   bsize, NOCRED, &bp)) != 0) {
404 			printf("Can't read sector %d of VDS\n", sector);
405 			goto bail;
406 		}
407 		lvd = (struct logvol_desc *)bp->b_data;
408 		if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) {
409 			udfmp->bsize = le32toh(lvd->lb_size);
410 			udfmp->bmask = udfmp->bsize - 1;
411 			udfmp->bshift = ffs(udfmp->bsize) - 1;
412 			fsd_part = le16toh(lvd->_lvd_use.fsd_loc.loc.part_num);
413 			fsd_offset = le32toh(lvd->_lvd_use.fsd_loc.loc.lb_num);
414 			if (udf_find_partmaps(udfmp, lvd))
415 				break;
416 			logvol_found = 1;
417 		}
418 		pd = (struct part_desc *)bp->b_data;
419 		if (!udf_checktag(&pd->tag, TAGID_PARTITION)) {
420 			part_found = 1;
421 			part_num = le16toh(pd->part_num);
422 			udfmp->part_len = le32toh(pd->part_len);
423 			udfmp->part_start = le32toh(pd->start_loc);
424 		}
425 
426 		brelse(bp);
427 		bp = NULL;
428 		if ((part_found) && (logvol_found))
429 			break;
430 	}
431 
432 	if (!part_found || !logvol_found) {
433 		error = EINVAL;
434 		goto bail;
435 	}
436 
437 	if (fsd_part != part_num) {
438 		printf("FSD does not lie within the partition!\n");
439 		error = EINVAL;
440 		goto bail;
441 	}
442 
443 
444 	/*
445 	 * Grab the Fileset Descriptor
446 	 * Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing
447 	 * me in the right direction here.
448 	 */
449 	sector = udfmp->part_start + fsd_offset;
450 	if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) {
451 		printf("Cannot read sector %d of FSD\n", sector);
452 		goto bail;
453 	}
454 	fsd = (struct fileset_desc *)bp->b_data;
455 	if (!udf_checktag(&fsd->tag, TAGID_FSD)) {
456 		fsd_found = 1;
457 		bcopy(&fsd->rootdir_icb, &udfmp->root_icb,
458 		    sizeof(struct long_ad));
459 	}
460 
461 	brelse(bp);
462 	bp = NULL;
463 
464 	if (!fsd_found) {
465 		printf("Couldn't find the fsd\n");
466 		error = EINVAL;
467 		goto bail;
468 	}
469 
470 	/*
471 	 * Find the file entry for the root directory.
472 	 */
473 	sector = le32toh(udfmp->root_icb.loc.lb_num) + udfmp->part_start;
474 	size = le32toh(udfmp->root_icb.len);
475 	if ((error = udf_readlblks(udfmp, sector, size, &bp)) != 0) {
476 		printf("Cannot read sector %d\n", sector);
477 		goto bail;
478 	}
479 
480 	root_fentry = (struct file_entry *)bp->b_data;
481 	if ((error = udf_checktag(&root_fentry->tag, TAGID_FENTRY))) {
482 		printf("Invalid root file entry!\n");
483 		goto bail;
484 	}
485 
486 	brelse(bp);
487 	bp = NULL;
488 
489 	return 0;
490 
491 bail:
492 	if (udfmp != NULL)
493 		FREE(udfmp, M_UDFMOUNT);
494 	if (bp != NULL)
495 		brelse(bp);
496 	DROP_GIANT();
497 	g_topology_lock();
498 	g_vfs_close(cp, td);
499 	g_topology_unlock();
500 	PICKUP_GIANT();
501 	return error;
502 };
503 
504 static int
505 udf_unmount(struct mount *mp, int mntflags, struct thread *td)
506 {
507 	struct udf_mnt *udfmp;
508 	int error, flags = 0;
509 
510 	udfmp = VFSTOUDFFS(mp);
511 
512 	if (mntflags & MNT_FORCE)
513 		flags |= FORCECLOSE;
514 
515 	if ((error = vflush(mp, 0, flags, td)))
516 		return (error);
517 
518 	if (udfmp->im_flags & UDFMNT_KICONV && udf_iconv) {
519 		if (udfmp->im_d2l)
520 			udf_iconv->close(udfmp->im_d2l);
521 #if 0
522 		if (udfmp->im_l2d)
523 			udf_iconv->close(udfmp->im_l2d);
524 #endif
525 	}
526 
527 	DROP_GIANT();
528 	g_topology_lock();
529 	g_vfs_close(udfmp->im_cp, td);
530 	g_topology_unlock();
531 	PICKUP_GIANT();
532 	vrele(udfmp->im_devvp);
533 
534 	if (udfmp->s_table != NULL)
535 		FREE(udfmp->s_table, M_UDFMOUNT);
536 
537 	FREE(udfmp, M_UDFMOUNT);
538 
539 	mp->mnt_data = (qaddr_t)0;
540 	mp->mnt_flag &= ~MNT_LOCAL;
541 
542 	return (0);
543 }
544 
545 static int
546 udf_root(struct mount *mp, int flags, struct vnode **vpp, struct thread *td)
547 {
548 	struct udf_mnt *udfmp;
549 	struct vnode *vp;
550 	ino_t id;
551 	int error;
552 
553 	udfmp = VFSTOUDFFS(mp);
554 
555 	id = udf_getid(&udfmp->root_icb);
556 
557 	error = udf_vget(mp, id, LK_EXCLUSIVE, vpp);
558 	if (error)
559 		return error;
560 
561 	vp = *vpp;
562 	vp->v_vflag |= VV_ROOT;
563 
564 	return (0);
565 }
566 
567 static int
568 udf_statfs(struct mount *mp, struct statfs *sbp, struct thread *td)
569 {
570 	struct udf_mnt *udfmp;
571 
572 	udfmp = VFSTOUDFFS(mp);
573 
574 	sbp->f_bsize = udfmp->bsize;
575 	sbp->f_iosize = udfmp->bsize;
576 	sbp->f_blocks = udfmp->part_len;
577 	sbp->f_bfree = 0;
578 	sbp->f_bavail = 0;
579 	sbp->f_files = 0;
580 	sbp->f_ffree = 0;
581 	return 0;
582 }
583 
584 int
585 udf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
586 {
587 	struct buf *bp;
588 	struct vnode *devvp;
589 	struct udf_mnt *udfmp;
590 	struct thread *td;
591 	struct vnode *vp;
592 	struct udf_node *unode;
593 	struct file_entry *fe;
594 	int error, sector, size;
595 
596 	error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL);
597 	if (error || *vpp != NULL)
598 		return (error);
599 
600 	td = curthread;
601 	udfmp = VFSTOUDFFS(mp);
602 
603 	unode = uma_zalloc(udf_zone_node, M_WAITOK | M_ZERO);
604 
605 	if ((error = udf_allocv(mp, &vp, td))) {
606 		printf("Error from udf_allocv\n");
607 		uma_zfree(udf_zone_node, unode);
608 		return (error);
609 	}
610 
611 	unode->i_vnode = vp;
612 	unode->hash_id = ino;
613 	unode->udfmp = udfmp;
614 	vp->v_data = unode;
615 
616 	error = vfs_hash_insert(vp, ino, flags, curthread, vpp, NULL, NULL);
617 	if (error || *vpp != NULL)
618 		return (error);
619 
620 	/*
621 	 * Copy in the file entry.  Per the spec, the size can only be 1 block.
622 	 */
623 	sector = ino + udfmp->part_start;
624 	devvp = udfmp->im_devvp;
625 	if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) {
626 		printf("Cannot read sector %d\n", sector);
627 		vput(vp);
628 		brelse(bp);
629 		*vpp = NULL;
630 		return (error);
631 	}
632 
633 	fe = (struct file_entry *)bp->b_data;
634 	if (udf_checktag(&fe->tag, TAGID_FENTRY)) {
635 		printf("Invalid file entry!\n");
636 		vput(vp);
637 		brelse(bp);
638 		*vpp = NULL;
639 		return (ENOMEM);
640 	}
641 	size = UDF_FENTRY_SIZE + le32toh(fe->l_ea) + le32toh(fe->l_ad);
642 	MALLOC(unode->fentry, struct file_entry *, size, M_UDFFENTRY,
643 	    M_NOWAIT | M_ZERO);
644 	if (unode->fentry == NULL) {
645 		printf("Cannot allocate file entry block\n");
646 		vput(vp);
647 		brelse(bp);
648 		*vpp = NULL;
649 		return (ENOMEM);
650 	}
651 
652 	bcopy(bp->b_data, unode->fentry, size);
653 
654 	brelse(bp);
655 	bp = NULL;
656 
657 	switch (unode->fentry->icbtag.file_type) {
658 	default:
659 		vp->v_type = VBAD;
660 		break;
661 	case 4:
662 		vp->v_type = VDIR;
663 		break;
664 	case 5:
665 		vp->v_type = VREG;
666 		break;
667 	case 6:
668 		vp->v_type = VBLK;
669 		break;
670 	case 7:
671 		vp->v_type = VCHR;
672 		break;
673 	case 9:
674 		vp->v_type = VFIFO;
675 		break;
676 	case 10:
677 		vp->v_type = VSOCK;
678 		break;
679 	case 12:
680 		vp->v_type = VLNK;
681 		break;
682 	}
683 	*vpp = vp;
684 
685 	return (0);
686 }
687 
688 struct ifid {
689 	u_short	ifid_len;
690 	u_short	ifid_pad;
691 	int	ifid_ino;
692 	long	ifid_start;
693 };
694 
695 static int
696 udf_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
697 {
698 	struct ifid *ifhp;
699 	struct vnode *nvp;
700 	int error;
701 
702 	ifhp = (struct ifid *)fhp;
703 
704 	if ((error = VFS_VGET(mp, ifhp->ifid_ino, LK_EXCLUSIVE, &nvp)) != 0) {
705 		*vpp = NULLVP;
706 		return (error);
707 	}
708 
709 	*vpp = nvp;
710 	vnode_create_vobject(*vpp, 0, curthread);
711 	return (0);
712 }
713 
714 static int
715 udf_vptofh (struct vnode *vp, struct fid *fhp)
716 {
717 	struct udf_node *node;
718 	struct ifid *ifhp;
719 
720 	node = VTON(vp);
721 	ifhp = (struct ifid *)fhp;
722 	ifhp->ifid_len = sizeof(struct ifid);
723 	ifhp->ifid_ino = node->hash_id;
724 
725 	return (0);
726 }
727 
728 static int
729 udf_find_partmaps(struct udf_mnt *udfmp, struct logvol_desc *lvd)
730 {
731 	union udf_pmap *pmap;
732 	struct part_map_spare *pms;
733 	struct regid *pmap_id;
734 	struct buf *bp;
735 	unsigned char regid_id[UDF_REGID_ID_SIZE + 1];
736 	int i, ptype, psize, error;
737 
738 	for (i = 0; i < le32toh(lvd->n_pm); i++) {
739 		pmap = (union udf_pmap *)&lvd->maps[i * UDF_PMAP_SIZE];
740 		ptype = pmap->data[0];
741 		psize = pmap->data[1];
742 		if (((ptype != 1) && (ptype != 2)) ||
743 		    ((psize != UDF_PMAP_SIZE) && (psize != 6))) {
744 			printf("Invalid partition map found\n");
745 			return (1);
746 		}
747 
748 		if (ptype == 1) {
749 			/* Type 1 map.  We don't care */
750 			continue;
751 		}
752 
753 		/* Type 2 map.  Gotta find out the details */
754 		pmap_id = (struct regid *)&pmap->data[4];
755 		bzero(&regid_id[0], UDF_REGID_ID_SIZE);
756 		bcopy(&pmap_id->id[0], &regid_id[0], UDF_REGID_ID_SIZE);
757 
758 		if (bcmp(&regid_id[0], "*UDF Sparable Partition",
759 		    UDF_REGID_ID_SIZE)) {
760 			printf("Unsupported partition map: %s\n", &regid_id[0]);
761 			return (1);
762 		}
763 
764 		pms = &pmap->pms;
765 		MALLOC(udfmp->s_table, struct udf_sparing_table *,
766 		    le32toh(pms->st_size), M_UDFMOUNT, M_NOWAIT | M_ZERO);
767 		if (udfmp->s_table == NULL)
768 			return (ENOMEM);
769 
770 		/* Calculate the number of sectors per packet. */
771 		/* XXX Logical or physical? */
772 		udfmp->p_sectors = le16toh(pms->packet_len) / udfmp->bsize;
773 
774 		/*
775 		 * XXX If reading the first Sparing Table fails, should look
776 		 * for another table.
777 		 */
778 		if ((error = udf_readlblks(udfmp, le32toh(pms->st_loc[0]),
779 					   le32toh(pms->st_size), &bp)) != 0) {
780 			if (bp != NULL)
781 				brelse(bp);
782 			printf("Failed to read Sparing Table at sector %d\n",
783 			    le32toh(pms->st_loc[0]));
784 			return (error);
785 		}
786 		bcopy(bp->b_data, udfmp->s_table, le32toh(pms->st_size));
787 		brelse(bp);
788 
789 		if (udf_checktag(&udfmp->s_table->tag, 0)) {
790 			printf("Invalid sparing table found\n");
791 			return (EINVAL);
792 		}
793 
794 		/* See how many valid entries there are here.  The list is
795 		 * supposed to be sorted. 0xfffffff0 and higher are not valid
796 		 */
797 		for (i = 0; i < le16toh(udfmp->s_table->rt_l); i++) {
798 			udfmp->s_table_entries = i;
799 			if (le32toh(udfmp->s_table->entries[i].org) >=
800 			    0xfffffff0)
801 				break;
802 		}
803 	}
804 
805 	return (0);
806 }
807