1*68cc3983Sjsg /* $OpenBSD: udf_vfsops.c,v 1.71 2023/04/13 02:19:05 jsg Exp $ */
2d9ac8608Spedro
3d9ac8608Spedro /*
4d9ac8608Spedro * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
5d9ac8608Spedro * All rights reserved.
6d9ac8608Spedro *
7d9ac8608Spedro * Redistribution and use in source and binary forms, with or without
8d9ac8608Spedro * modification, are permitted provided that the following conditions
9d9ac8608Spedro * are met:
10d9ac8608Spedro * 1. Redistributions of source code must retain the above copyright
11d9ac8608Spedro * notice, this list of conditions and the following disclaimer.
12d9ac8608Spedro * 2. Redistributions in binary form must reproduce the above copyright
13d9ac8608Spedro * notice, this list of conditions and the following disclaimer in the
14d9ac8608Spedro * documentation and/or other materials provided with the distribution.
15d9ac8608Spedro *
16d9ac8608Spedro * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17d9ac8608Spedro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d9ac8608Spedro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19d9ac8608Spedro * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20d9ac8608Spedro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21d9ac8608Spedro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22d9ac8608Spedro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23d9ac8608Spedro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24d9ac8608Spedro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25d9ac8608Spedro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26d9ac8608Spedro * SUCH DAMAGE.
27d9ac8608Spedro *
28d9ac8608Spedro * $FreeBSD: src/sys/fs/udf/udf_vfsops.c,v 1.25 2005/01/25 15:52:03 phk Exp $
29d9ac8608Spedro */
30d9ac8608Spedro
31d9ac8608Spedro /*
32fcbf5195Sjmc * Ported to OpenBSD by Pedro Martelletto in February 2005.
33d9ac8608Spedro */
34d9ac8608Spedro
35d9ac8608Spedro /*
36d9ac8608Spedro * Ok, here's how it goes. The UDF specs are pretty clear on how each data
37d9ac8608Spedro * structure is made up, but not very clear on how they relate to each other.
380d297f47Sjsg * Here is the skinny... This demonstrates a filesystem with one file in the
39d9ac8608Spedro * root directory. Subdirectories are treated just as normal files, but they
40d9ac8608Spedro * have File Id Descriptors of their children as their file data. As for the
41d9ac8608Spedro * Anchor Volume Descriptor Pointer, it can exist in two of the following three
42d9ac8608Spedro * places: sector 256, sector n (the max sector of the disk), or sector
43d9ac8608Spedro * n - 256. It's a pretty good bet that one will exist at sector 256 though.
44d9ac8608Spedro * One caveat is unclosed CD media. For that, sector 256 cannot be written,
45d9ac8608Spedro * so the Anchor Volume Descriptor Pointer can exist at sector 512 until the
46d9ac8608Spedro * media is closed.
47d9ac8608Spedro */
48d9ac8608Spedro
49d9ac8608Spedro #include <sys/param.h>
50d9ac8608Spedro #include <sys/systm.h>
51d9ac8608Spedro #include <sys/uio.h>
52d9ac8608Spedro #include <sys/buf.h>
53d9ac8608Spedro #include <sys/dirent.h>
54d9ac8608Spedro #include <sys/fcntl.h>
55d9ac8608Spedro #include <sys/kernel.h>
56d9ac8608Spedro #include <sys/malloc.h>
57d9ac8608Spedro #include <sys/mutex.h>
58d9ac8608Spedro #include <sys/mount.h>
59d9ac8608Spedro #include <sys/namei.h>
60d9ac8608Spedro #include <sys/pool.h>
61d9ac8608Spedro #include <sys/proc.h>
62d9ac8608Spedro #include <sys/lock.h>
63d9ac8608Spedro #include <sys/queue.h>
64d9ac8608Spedro #include <sys/vnode.h>
65d9ac8608Spedro #include <sys/endian.h>
66544451c3Sderaadt #include <sys/specdev.h>
67d9ac8608Spedro
689dc9bb81Sdlg #include <crypto/siphash.h>
699dc9bb81Sdlg
70d9ac8608Spedro #include <isofs/udf/ecma167-udf.h>
71d9ac8608Spedro #include <isofs/udf/udf.h>
72d9ac8608Spedro #include <isofs/udf/udf_extern.h>
73d9ac8608Spedro
74d9ac8608Spedro struct pool udf_trans_pool;
75797916ccSpedro struct pool unode_pool;
76d9ac8608Spedro struct pool udf_ds_pool;
77d9ac8608Spedro
78884fd684Spedro int udf_find_partmaps(struct umount *, struct logvol_desc *);
79884fd684Spedro int udf_get_vpartmap(struct umount *, struct part_map_virt *);
80884fd684Spedro int udf_get_spartmap(struct umount *, struct part_map_spare *);
81b077103dSkrw int udf_get_mpartmap(struct umount *, struct part_map_meta *);
82e1a8e762Spedro int udf_mountfs(struct vnode *, struct mount *, uint32_t, struct proc *);
83d9ac8608Spedro
84d9ac8608Spedro const struct vfsops udf_vfsops = {
85d9ac8608Spedro .vfs_mount = udf_mount,
86d9ac8608Spedro .vfs_start = udf_start,
8741f642fcSbluhm .vfs_unmount = udf_unmount,
88d9ac8608Spedro .vfs_root = udf_root,
89d9ac8608Spedro .vfs_quotactl = udf_quotactl,
90d9ac8608Spedro .vfs_statfs = udf_statfs,
91d9ac8608Spedro .vfs_sync = udf_sync,
92d9ac8608Spedro .vfs_vget = udf_vget,
9341f642fcSbluhm .vfs_fhtovp = udf_fhtovp,
94d9ac8608Spedro .vfs_vptofh = udf_vptofh,
9541f642fcSbluhm .vfs_init = udf_init,
96d9ac8608Spedro .vfs_sysctl = udf_sysctl,
97d9ac8608Spedro .vfs_checkexp = udf_checkexp,
98d9ac8608Spedro };
99d9ac8608Spedro
100d9ac8608Spedro int
udf_init(struct vfsconf * foo)101d9ac8608Spedro udf_init(struct vfsconf *foo)
102d9ac8608Spedro {
1031378bae2Sdlg pool_init(&udf_trans_pool, MAXNAMLEN * sizeof(unicode_t), 0, IPL_NONE,
104ba576a21Skettenis PR_WAITOK, "udftrpl", NULL);
1051378bae2Sdlg pool_init(&unode_pool, sizeof(struct unode), 0, IPL_NONE,
106ba576a21Skettenis PR_WAITOK, "udfndpl", NULL);
1071378bae2Sdlg pool_init(&udf_ds_pool, sizeof(struct udf_dirstream), 0, IPL_NONE,
108ba576a21Skettenis PR_WAITOK, "udfdspl", NULL);
109d9ac8608Spedro
110d9ac8608Spedro return (0);
111d9ac8608Spedro }
112d9ac8608Spedro
113d9ac8608Spedro int
udf_start(struct mount * mp,int flags,struct proc * p)114d9ac8608Spedro udf_start(struct mount *mp, int flags, struct proc *p)
115d9ac8608Spedro {
116d9ac8608Spedro return (0);
117d9ac8608Spedro }
118d9ac8608Spedro
119d9ac8608Spedro int
udf_mount(struct mount * mp,const char * path,void * data,struct nameidata * ndp,struct proc * p)120d9ac8608Spedro udf_mount(struct mount *mp, const char *path, void *data,
121d9ac8608Spedro struct nameidata *ndp, struct proc *p)
122d9ac8608Spedro {
123d9ac8608Spedro struct vnode *devvp; /* vnode of the mount device */
1247efda1a1Sderaadt struct udf_args *args = data;
125a93bb724Sjsing char fspec[MNAMELEN];
126d9ac8608Spedro int error;
127d9ac8608Spedro
128d9ac8608Spedro if ((mp->mnt_flag & MNT_RDONLY) == 0) {
129d9ac8608Spedro mp->mnt_flag |= MNT_RDONLY;
130678d037dSjolan #ifdef UDF_DEBUG
131d9ac8608Spedro printf("udf_mount: enforcing read-only mode\n");
132678d037dSjolan #endif
133d9ac8608Spedro }
134d9ac8608Spedro
135d9ac8608Spedro /*
136d9ac8608Spedro * No root filesystem support. Probably not a big deal, since the
137d9ac8608Spedro * bootloader doesn't understand UDF.
138d9ac8608Spedro */
139d9ac8608Spedro if (mp->mnt_flag & MNT_ROOTFS)
140d9ac8608Spedro return (EOPNOTSUPP);
141d9ac8608Spedro
1427efda1a1Sderaadt /*
1437efda1a1Sderaadt * If updating, check whether changing from read-only to
1447efda1a1Sderaadt * read/write; if there is no device name, that's all we do.
1457efda1a1Sderaadt */
1467efda1a1Sderaadt if (mp->mnt_flag & MNT_UPDATE) {
1477efda1a1Sderaadt return (0);
1487efda1a1Sderaadt }
149d9ac8608Spedro
1507efda1a1Sderaadt error = copyinstr(args->fspec, fspec, sizeof(fspec), NULL);
151a93bb724Sjsing if (error)
152a93bb724Sjsing return (error);
153a93bb724Sjsing
154a93bb724Sjsing NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, p);
155d9ac8608Spedro if ((error = namei(ndp)))
156d9ac8608Spedro return (error);
157d9ac8608Spedro
158d9ac8608Spedro devvp = ndp->ni_vp;
159d9ac8608Spedro if (devvp->v_type != VBLK) {
160d9ac8608Spedro vrele(devvp);
161d9ac8608Spedro return (ENOTBLK);
162d9ac8608Spedro }
163d9ac8608Spedro
164d9ac8608Spedro if (major(devvp->v_rdev) >= nblkdev) {
165d9ac8608Spedro vrele(devvp);
166d9ac8608Spedro return (ENXIO);
167d9ac8608Spedro }
168d9ac8608Spedro
1697efda1a1Sderaadt if ((error = udf_mountfs(devvp, mp, args->lastblock, p))) {
170d9ac8608Spedro vrele(devvp);
171d9ac8608Spedro return (error);
172d9ac8608Spedro }
173d9ac8608Spedro
174d9ac8608Spedro /*
175d9ac8608Spedro * Keep a copy of the mount information.
176d9ac8608Spedro */
177a93bb724Sjsing bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
178a93bb724Sjsing strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
179a93bb724Sjsing bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
180a93bb724Sjsing strlcpy(mp->mnt_stat.f_mntfromname, fspec, MNAMELEN);
181aec3986eSjsing bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN);
182aec3986eSjsing strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN);
183d9ac8608Spedro
184d9ac8608Spedro return (0);
185d9ac8608Spedro };
186d9ac8608Spedro
187d9ac8608Spedro /*
188d9ac8608Spedro * Check the descriptor tag for both the correct id and correct checksum.
189d9ac8608Spedro * Return zero if all is good, EINVAL if not.
190d9ac8608Spedro */
191d9ac8608Spedro int
udf_checktag(struct desc_tag * tag,uint16_t id)192d9ac8608Spedro udf_checktag(struct desc_tag *tag, uint16_t id)
193d9ac8608Spedro {
194d9ac8608Spedro uint8_t *itag;
195d9ac8608Spedro uint8_t i, cksum = 0;
196d9ac8608Spedro
197d9ac8608Spedro itag = (uint8_t *)tag;
198d9ac8608Spedro
199da6a5abdSpedro if (letoh16(tag->id) != id)
200d9ac8608Spedro return (EINVAL);
201d9ac8608Spedro
202d9ac8608Spedro for (i = 0; i < 15; i++)
203d9ac8608Spedro cksum = cksum + itag[i];
204d9ac8608Spedro cksum = cksum - itag[4];
205d9ac8608Spedro
206d9ac8608Spedro if (cksum == tag->cksum)
207d9ac8608Spedro return (0);
208d9ac8608Spedro
209d9ac8608Spedro return (EINVAL);
210d9ac8608Spedro }
211d9ac8608Spedro
212d9ac8608Spedro int
udf_mountfs(struct vnode * devvp,struct mount * mp,uint32_t lb,struct proc * p)213e1a8e762Spedro udf_mountfs(struct vnode *devvp, struct mount *mp, uint32_t lb, struct proc *p)
214220408b5Spat {
215d9ac8608Spedro struct buf *bp = NULL;
216d9ac8608Spedro struct anchor_vdp avdp;
217170e22feSpedro struct umount *ump = NULL;
218d9ac8608Spedro struct part_desc *pd;
219d9ac8608Spedro struct logvol_desc *lvd;
220d9ac8608Spedro struct fileset_desc *fsd;
221b077103dSkrw struct extfile_entry *xfentry;
222b077103dSkrw struct file_entry *fentry;
223d9ac8608Spedro uint32_t sector, size, mvds_start, mvds_end;
224d9ac8608Spedro uint32_t fsd_offset = 0;
225d9ac8608Spedro uint16_t part_num = 0, fsd_part = 0;
226d9ac8608Spedro int error = EINVAL;
227d9ac8608Spedro int logvol_found = 0, part_found = 0, fsd_found = 0;
228d9ac8608Spedro int bsize;
229d9ac8608Spedro
230d9ac8608Spedro /*
231d9ac8608Spedro * Disallow multiple mounts of the same device.
232d9ac8608Spedro * Disallow mounting of a device that is currently in use
233d9ac8608Spedro * (except for root, which might share swap device for miniroot).
234d9ac8608Spedro * Flush out any old buffers remaining from a previous use.
235d9ac8608Spedro */
236d9ac8608Spedro if ((error = vfs_mountedon(devvp)))
237d9ac8608Spedro return (error);
238d9ac8608Spedro if (vcount(devvp) > 1 && devvp != rootvp)
239d9ac8608Spedro return (EBUSY);
2406e880534Svisa vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
241a8d7c3beScheloha error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, INFSLP);
24236bb23f1Svisa VOP_UNLOCK(devvp);
243d9ac8608Spedro if (error)
244d9ac8608Spedro return (error);
245d9ac8608Spedro
246d9ac8608Spedro error = VOP_OPEN(devvp, FREAD, FSCRED, p);
247d9ac8608Spedro if (error)
248d9ac8608Spedro return (error);
249d9ac8608Spedro
250c86f0003Skrw ump = malloc(sizeof(*ump), M_UDFMOUNT, M_WAITOK | M_ZERO);
251d9ac8608Spedro
25241e0c475Sguenther mp->mnt_data = ump;
253d9ac8608Spedro mp->mnt_stat.f_fsid.val[0] = devvp->v_rdev;
2547d8a2b95Stedu mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
255f28dec03Snatano mp->mnt_stat.f_namemax = NAME_MAX;
256d9ac8608Spedro mp->mnt_flag |= MNT_LOCAL;
257170e22feSpedro
258170e22feSpedro ump->um_mountp = mp;
259170e22feSpedro ump->um_dev = devvp->v_rdev;
260170e22feSpedro ump->um_devvp = devvp;
261d9ac8608Spedro
262c184c659Spedro bsize = 2048; /* Should probe the media for its size. */
263d9ac8608Spedro
264d9ac8608Spedro /*
265d9ac8608Spedro * Get the Anchor Volume Descriptor Pointer from sector 256.
266c184c659Spedro * Should also check sector n - 256, n, and 512.
267d9ac8608Spedro */
268d9ac8608Spedro sector = 256;
26993f62a9eStedu if ((error = bread(devvp, sector * btodb(bsize), bsize, &bp)) != 0)
270d9ac8608Spedro goto bail;
271d9ac8608Spedro if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)))
272d9ac8608Spedro goto bail;
273d9ac8608Spedro
274d9ac8608Spedro bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp));
275d9ac8608Spedro brelse(bp);
276d9ac8608Spedro bp = NULL;
277d9ac8608Spedro
278d9ac8608Spedro /*
279d9ac8608Spedro * Extract the Partition Descriptor and Logical Volume Descriptor
280d9ac8608Spedro * from the Volume Descriptor Sequence.
281c184c659Spedro * Should we care about the partition type right now?
282c184c659Spedro * What about multiple partitions?
283d9ac8608Spedro */
284d9ac8608Spedro mvds_start = letoh32(avdp.main_vds_ex.loc);
285d9ac8608Spedro mvds_end = mvds_start + (letoh32(avdp.main_vds_ex.len) - 1) / bsize;
286d9ac8608Spedro for (sector = mvds_start; sector < mvds_end; sector++) {
287d9ac8608Spedro if ((error = bread(devvp, sector * btodb(bsize), bsize,
28893f62a9eStedu &bp)) != 0) {
289d9ac8608Spedro printf("Can't read sector %d of VDS\n", sector);
290d9ac8608Spedro goto bail;
291d9ac8608Spedro }
292d9ac8608Spedro lvd = (struct logvol_desc *)bp->b_data;
293d9ac8608Spedro if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) {
294170e22feSpedro ump->um_bsize = letoh32(lvd->lb_size);
295170e22feSpedro ump->um_bmask = ump->um_bsize - 1;
296170e22feSpedro ump->um_bshift = ffs(ump->um_bsize) - 1;
297d9ac8608Spedro fsd_part = letoh16(lvd->_lvd_use.fsd_loc.loc.part_num);
298d9ac8608Spedro fsd_offset = letoh32(lvd->_lvd_use.fsd_loc.loc.lb_num);
299170e22feSpedro if (udf_find_partmaps(ump, lvd))
300d9ac8608Spedro break;
301d9ac8608Spedro logvol_found = 1;
302d9ac8608Spedro }
303d9ac8608Spedro pd = (struct part_desc *)bp->b_data;
304d9ac8608Spedro if (!udf_checktag(&pd->tag, TAGID_PARTITION)) {
305d9ac8608Spedro part_found = 1;
306d9ac8608Spedro part_num = letoh16(pd->part_num);
307b077103dSkrw ump->um_len = ump->um_reallen = letoh32(pd->part_len);
308b077103dSkrw ump->um_start = ump->um_realstart = letoh32(pd->start_loc);
309d9ac8608Spedro }
310d9ac8608Spedro
311d9ac8608Spedro brelse(bp);
312d9ac8608Spedro bp = NULL;
313d9ac8608Spedro if ((part_found) && (logvol_found))
314d9ac8608Spedro break;
315d9ac8608Spedro }
316d9ac8608Spedro
317d9ac8608Spedro if (!part_found || !logvol_found) {
318d9ac8608Spedro error = EINVAL;
319d9ac8608Spedro goto bail;
320d9ac8608Spedro }
321d9ac8608Spedro
322b077103dSkrw if (ISSET(ump->um_flags, UDF_MNT_USES_META)) {
323b077103dSkrw /* Read Metadata File 'File Entry' to find Metadata file. */
324b077103dSkrw struct long_ad *la;
325b077103dSkrw sector = ump->um_start + ump->um_meta_start; /* Set in udf_get_mpartmap() */
326b077103dSkrw if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
327b077103dSkrw printf("Cannot read sector %d for Metadata File Entry\n", sector);
328b077103dSkrw error = EINVAL;
329b077103dSkrw goto bail;
330b077103dSkrw }
331b077103dSkrw xfentry = (struct extfile_entry *)bp->b_data;
332b077103dSkrw fentry = (struct file_entry *)bp->b_data;
333b077103dSkrw if (udf_checktag(&xfentry->tag, TAGID_EXTFENTRY) == 0)
334b077103dSkrw la = (struct long_ad *)&xfentry->data[letoh32(xfentry->l_ea)];
335b077103dSkrw else if (udf_checktag(&fentry->tag, TAGID_FENTRY) == 0)
336b077103dSkrw la = (struct long_ad *)&fentry->data[letoh32(fentry->l_ea)];
337b077103dSkrw else {
338b077103dSkrw printf("Invalid Metadata File FE @ sector %d! (tag.id %d)\n",
339b077103dSkrw sector, fentry->tag.id);
340b077103dSkrw error = EINVAL;
341b077103dSkrw goto bail;
342b077103dSkrw }
343b077103dSkrw ump->um_meta_start = letoh32(la->loc.lb_num);
344b077103dSkrw ump->um_meta_len = letoh32(la->len);
345b077103dSkrw if (bp != NULL) {
346b077103dSkrw brelse(bp);
347b077103dSkrw bp = NULL;
348b077103dSkrw }
349b077103dSkrw } else if (fsd_part != part_num) {
350d9ac8608Spedro printf("FSD does not lie within the partition!\n");
351d9ac8608Spedro error = EINVAL;
352d9ac8608Spedro goto bail;
353d9ac8608Spedro }
354d9ac8608Spedro
355170e22feSpedro mtx_init(&ump->um_hashmtx, IPL_NONE);
356170e22feSpedro ump->um_hashtbl = hashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, M_WAITOK,
357170e22feSpedro &ump->um_hashsz);
3589dc9bb81Sdlg arc4random_buf(&ump->um_hashkey, sizeof(ump->um_hashkey));
3598eb7f8cbSpedro
3608eb7f8cbSpedro /* Get the VAT, if needed */
361170e22feSpedro if (ump->um_flags & UDF_MNT_FIND_VAT) {
362e1a8e762Spedro error = udf_vat_get(ump, lb);
3638eb7f8cbSpedro if (error)
3648eb7f8cbSpedro goto bail;
3658eb7f8cbSpedro }
366d9ac8608Spedro
367d9ac8608Spedro /*
368d9ac8608Spedro * Grab the Fileset Descriptor
369d9ac8608Spedro * Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing
370d9ac8608Spedro * me in the right direction here.
371d9ac8608Spedro */
372b077103dSkrw
373b077103dSkrw if (ISSET(ump->um_flags, UDF_MNT_USES_META))
374b077103dSkrw sector = ump->um_meta_start;
375b077103dSkrw else
3768eb7f8cbSpedro sector = fsd_offset;
377170e22feSpedro udf_vat_map(ump, §or);
378170e22feSpedro if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
379d9ac8608Spedro printf("Cannot read sector %d of FSD\n", sector);
380d9ac8608Spedro goto bail;
381d9ac8608Spedro }
382d9ac8608Spedro fsd = (struct fileset_desc *)bp->b_data;
383d9ac8608Spedro if (!udf_checktag(&fsd->tag, TAGID_FSD)) {
384d9ac8608Spedro fsd_found = 1;
385170e22feSpedro bcopy(&fsd->rootdir_icb, &ump->um_root_icb,
386d9ac8608Spedro sizeof(struct long_ad));
387b077103dSkrw if (ISSET(ump->um_flags, UDF_MNT_USES_META)) {
388b077103dSkrw ump->um_root_icb.loc.lb_num += ump->um_meta_start;
389b077103dSkrw ump->um_root_icb.loc.part_num = part_num;
390b077103dSkrw }
391d9ac8608Spedro }
392d9ac8608Spedro
393d9ac8608Spedro brelse(bp);
394d9ac8608Spedro bp = NULL;
395d9ac8608Spedro
396d9ac8608Spedro if (!fsd_found) {
397d9ac8608Spedro printf("Couldn't find the fsd\n");
398d9ac8608Spedro error = EINVAL;
399d9ac8608Spedro goto bail;
400d9ac8608Spedro }
401d9ac8608Spedro
402d9ac8608Spedro /*
403d9ac8608Spedro * Find the file entry for the root directory.
404d9ac8608Spedro */
405170e22feSpedro sector = letoh32(ump->um_root_icb.loc.lb_num);
406170e22feSpedro size = letoh32(ump->um_root_icb.len);
407170e22feSpedro udf_vat_map(ump, §or);
408170e22feSpedro if ((error = udf_readlblks(ump, sector, size, &bp)) != 0) {
409d9ac8608Spedro printf("Cannot read sector %d\n", sector);
410d9ac8608Spedro goto bail;
411d9ac8608Spedro }
412d9ac8608Spedro
413b077103dSkrw xfentry = (struct extfile_entry *)bp->b_data;
414b077103dSkrw fentry = (struct file_entry *)bp->b_data;
415b077103dSkrw error = udf_checktag(&xfentry->tag, TAGID_EXTFENTRY);
416b077103dSkrw if (error) {
417b077103dSkrw error = udf_checktag(&fentry->tag, TAGID_FENTRY);
418b077103dSkrw if (error) {
419d9ac8608Spedro printf("Invalid root file entry!\n");
420d9ac8608Spedro goto bail;
421d9ac8608Spedro }
422b077103dSkrw }
423d9ac8608Spedro
424d9ac8608Spedro brelse(bp);
425d9ac8608Spedro bp = NULL;
426d9ac8608Spedro
427d9ac8608Spedro devvp->v_specmountpoint = mp;
428d9ac8608Spedro
429d9ac8608Spedro return (0);
430d9ac8608Spedro
431d9ac8608Spedro bail:
432fc852cf7Skrw if (ump != NULL) {
4330327e84aSjsg hashfree(ump->um_hashtbl, UDF_HASHTBLSIZE, M_UDFMOUNT);
434fc852cf7Skrw free(ump, M_UDFMOUNT, 0);
435220408b5Spat mp->mnt_data = NULL;
436220408b5Spat mp->mnt_flag &= ~MNT_LOCAL;
437fc852cf7Skrw }
4389ee302b8Sbluhm if (devvp->v_specinfo)
4399ee302b8Sbluhm devvp->v_specmountpoint = NULL;
440d9ac8608Spedro if (bp != NULL)
441d9ac8608Spedro brelse(bp);
44224f9a445Skrw
4436e880534Svisa vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY);
444d9ac8608Spedro VOP_CLOSE(devvp, FREAD, FSCRED, p);
44536bb23f1Svisa VOP_UNLOCK(devvp);
446d9ac8608Spedro
447d9ac8608Spedro return (error);
448220408b5Spat }
449d9ac8608Spedro
450d9ac8608Spedro int
udf_unmount(struct mount * mp,int mntflags,struct proc * p)451d9ac8608Spedro udf_unmount(struct mount *mp, int mntflags, struct proc *p)
452d9ac8608Spedro {
453170e22feSpedro struct umount *ump;
454d9ac8608Spedro struct vnode *devvp;
455d9ac8608Spedro int error, flags = 0;
456d9ac8608Spedro
457170e22feSpedro ump = VFSTOUDFFS(mp);
458170e22feSpedro devvp = ump->um_devvp;
459d9ac8608Spedro
460d9ac8608Spedro if (mntflags & MNT_FORCE)
461d9ac8608Spedro flags |= FORCECLOSE;
462d9ac8608Spedro
463d9ac8608Spedro if ((error = vflush(mp, NULL, flags)))
464d9ac8608Spedro return (error);
465d9ac8608Spedro
4666e880534Svisa vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
467a8d7c3beScheloha vinvalbuf(devvp, V_SAVE, NOCRED, p, 0, INFSLP);
4684b1ae25eSbluhm (void)VOP_CLOSE(devvp, FREAD, NOCRED, p);
46936bb23f1Svisa VOP_UNLOCK(devvp);
470d9ac8608Spedro
471d9ac8608Spedro devvp->v_specmountpoint = NULL;
472d9ac8608Spedro vrele(devvp);
473d9ac8608Spedro
474b97bc9b1Spedro if (ump->um_flags & UDF_MNT_USES_VAT)
4750e5ae731Stedu free(ump->um_vat, M_UDFMOUNT, 0);
476b97bc9b1Spedro
477170e22feSpedro if (ump->um_stbl != NULL)
4780e5ae731Stedu free(ump->um_stbl, M_UDFMOUNT, 0);
479d9ac8608Spedro
480f9b8b876Stedu hashfree(ump->um_hashtbl, UDF_HASHTBLSIZE, M_UDFMOUNT);
4810e5ae731Stedu free(ump, M_UDFMOUNT, 0);
482d9ac8608Spedro
483200e77f4Sbluhm mp->mnt_data = NULL;
484d9ac8608Spedro mp->mnt_flag &= ~MNT_LOCAL;
485d9ac8608Spedro
486d9ac8608Spedro return (0);
487d9ac8608Spedro }
488d9ac8608Spedro
489d9ac8608Spedro int
udf_root(struct mount * mp,struct vnode ** vpp)490d9ac8608Spedro udf_root(struct mount *mp, struct vnode **vpp)
491d9ac8608Spedro {
492170e22feSpedro struct umount *ump;
493d9ac8608Spedro struct vnode *vp;
4940cad8b22Sguenther udfino_t id;
495d9ac8608Spedro int error;
496d9ac8608Spedro
497170e22feSpedro ump = VFSTOUDFFS(mp);
498d9ac8608Spedro
499170e22feSpedro id = udf_getid(&ump->um_root_icb);
500d9ac8608Spedro
501d9ac8608Spedro error = udf_vget(mp, id, vpp);
502d9ac8608Spedro if (error)
503d9ac8608Spedro return (error);
504d9ac8608Spedro
505d9ac8608Spedro vp = *vpp;
506d9ac8608Spedro vp->v_flag |= VROOT;
507d9ac8608Spedro
508d9ac8608Spedro return (0);
509d9ac8608Spedro }
510d9ac8608Spedro
511d9ac8608Spedro int
udf_quotactl(struct mount * mp,int cmds,uid_t uid,caddr_t arg,struct proc * p)512d9ac8608Spedro udf_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
513d9ac8608Spedro struct proc *p)
514d9ac8608Spedro {
515d9ac8608Spedro return (EOPNOTSUPP);
516d9ac8608Spedro }
517d9ac8608Spedro
518d9ac8608Spedro int
udf_statfs(struct mount * mp,struct statfs * sbp,struct proc * p)519d9ac8608Spedro udf_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
520d9ac8608Spedro {
521170e22feSpedro struct umount *ump;
522d9ac8608Spedro
523170e22feSpedro ump = VFSTOUDFFS(mp);
524d9ac8608Spedro
525170e22feSpedro sbp->f_bsize = ump->um_bsize;
526170e22feSpedro sbp->f_iosize = ump->um_bsize;
527170e22feSpedro sbp->f_blocks = ump->um_len;
528d9ac8608Spedro sbp->f_bfree = 0;
529d9ac8608Spedro sbp->f_bavail = 0;
530d9ac8608Spedro sbp->f_files = 0;
531d9ac8608Spedro sbp->f_ffree = 0;
532f28dec03Snatano sbp->f_favail = 0;
533f28dec03Snatano copy_statfs_info(sbp, mp);
534d9ac8608Spedro
535d9ac8608Spedro return (0);
536d9ac8608Spedro }
537d9ac8608Spedro
538d9ac8608Spedro int
udf_sync(struct mount * mp,int waitfor,int stall,struct ucred * cred,struct proc * p)539976e9839Sderaadt udf_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred, struct proc *p)
540d9ac8608Spedro {
541d9ac8608Spedro return (0);
542d9ac8608Spedro }
543d9ac8608Spedro
544d9ac8608Spedro int
udf_vget(struct mount * mp,ino_t ino,struct vnode ** vpp)545d9ac8608Spedro udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
546d9ac8608Spedro {
547d9ac8608Spedro struct buf *bp;
548d9ac8608Spedro struct vnode *devvp;
549170e22feSpedro struct umount *ump;
550d9ac8608Spedro struct proc *p;
551b077103dSkrw struct vnode *vp, *nvp;
5521af96cccSpedro struct unode *up;
553b077103dSkrw struct extfile_entry *xfe;
554d9ac8608Spedro struct file_entry *fe;
5550cad8b22Sguenther uint32_t sector;
5560cad8b22Sguenther int error, size;
5570cad8b22Sguenther
5580cad8b22Sguenther if (ino > (udfino_t)-1)
5590cad8b22Sguenther panic("udf_vget: alien ino_t %llu", (unsigned long long)ino);
560d9ac8608Spedro
561d9ac8608Spedro p = curproc;
56234f51be2Spedro bp = NULL;
563d9ac8608Spedro *vpp = NULL;
564170e22feSpedro ump = VFSTOUDFFS(mp);
565d9ac8608Spedro
566d9ac8608Spedro /* See if we already have this in the cache */
567170e22feSpedro if ((error = udf_hashlookup(ump, ino, LK_EXCLUSIVE, vpp)) != 0)
568d9ac8608Spedro return (error);
569d9ac8608Spedro if (*vpp != NULL)
570d9ac8608Spedro return (0);
571d9ac8608Spedro
572d9ac8608Spedro /*
573d9ac8608Spedro * Allocate memory and check the tag id's before grabbing a new
574d9ac8608Spedro * vnode, since it's hard to roll back if there is a problem.
575d9ac8608Spedro */
576920b9ef6Smk up = pool_get(&unode_pool, PR_WAITOK | PR_ZERO);
577d9ac8608Spedro
578d9ac8608Spedro /*
579d9ac8608Spedro * Copy in the file entry. Per the spec, the size can only be 1 block.
580d9ac8608Spedro */
5818eb7f8cbSpedro sector = ino;
582170e22feSpedro devvp = ump->um_devvp;
583170e22feSpedro udf_vat_map(ump, §or);
584170e22feSpedro if ((error = RDSECTOR(devvp, sector, ump->um_bsize, &bp)) != 0) {
585d9ac8608Spedro printf("Cannot read sector %d\n", sector);
5861af96cccSpedro pool_put(&unode_pool, up);
58734f51be2Spedro if (bp != NULL)
58834f51be2Spedro brelse(bp);
589d9ac8608Spedro return (error);
590d9ac8608Spedro }
591d9ac8608Spedro
592b077103dSkrw xfe = (struct extfile_entry *)bp->b_data;
593d9ac8608Spedro fe = (struct file_entry *)bp->b_data;
594b077103dSkrw error = udf_checktag(&xfe->tag, TAGID_EXTFENTRY);
595b077103dSkrw if (error == 0) {
596b077103dSkrw size = letoh32(xfe->l_ea) + letoh32(xfe->l_ad);
597b077103dSkrw } else {
598b077103dSkrw error = udf_checktag(&fe->tag, TAGID_FENTRY);
599b077103dSkrw if (error) {
600d9ac8608Spedro printf("Invalid file entry!\n");
6011af96cccSpedro pool_put(&unode_pool, up);
602b077103dSkrw if (bp != NULL)
603d9ac8608Spedro brelse(bp);
604d9ac8608Spedro return (ENOMEM);
605b077103dSkrw } else
606b077103dSkrw size = letoh32(fe->l_ea) + letoh32(fe->l_ad);
607d9ac8608Spedro }
6085921d099Spedro
609b077103dSkrw /* Allocate max size of FE/XFE. */
610b077103dSkrw up->u_fentry = malloc(size + UDF_EXTFENTRY_SIZE, M_UDFFENTRY, M_NOWAIT | M_ZERO);
6111af96cccSpedro if (up->u_fentry == NULL) {
6121af96cccSpedro pool_put(&unode_pool, up);
613b077103dSkrw if (bp != NULL)
614d9ac8608Spedro brelse(bp);
6155921d099Spedro return (ENOMEM); /* Cannot allocate file entry block */
616d9ac8608Spedro }
617d9ac8608Spedro
618b077103dSkrw if (udf_checktag(&xfe->tag, TAGID_EXTFENTRY) == 0)
619b077103dSkrw bcopy(bp->b_data, up->u_fentry, size + UDF_EXTFENTRY_SIZE);
620b077103dSkrw else
621b077103dSkrw bcopy(bp->b_data, up->u_fentry, size + UDF_FENTRY_SIZE);
622d9ac8608Spedro
623d9ac8608Spedro brelse(bp);
624d9ac8608Spedro bp = NULL;
625d9ac8608Spedro
626d9ac8608Spedro if ((error = udf_allocv(mp, &vp, p))) {
6270e5ae731Stedu free(up->u_fentry, M_UDFFENTRY, 0);
6281af96cccSpedro pool_put(&unode_pool, up);
6295921d099Spedro return (error); /* Error from udf_allocv() */
630d9ac8608Spedro }
631d9ac8608Spedro
6321af96cccSpedro up->u_vnode = vp;
6331af96cccSpedro up->u_ino = ino;
634170e22feSpedro up->u_devvp = ump->um_devvp;
635170e22feSpedro up->u_dev = ump->um_dev;
636170e22feSpedro up->u_ump = ump;
6371af96cccSpedro vp->v_data = up;
638627b2c48Sthib vref(ump->um_devvp);
639d9ac8608Spedro
640d78cb2ffSvisa rrw_init_flags(&up->u_lock, "unode", RWL_DUPOK | RWL_IS_VNODE);
641d9ac8608Spedro
642d9ac8608Spedro /*
643d9ac8608Spedro * udf_hashins() will lock the vnode for us.
644d9ac8608Spedro */
6451af96cccSpedro udf_hashins(up);
646d9ac8608Spedro
6471af96cccSpedro switch (up->u_fentry->icbtag.file_type) {
648d9ac8608Spedro default:
649b077103dSkrw printf("Unrecognized file type (%d)\n", vp->v_type);
650b077103dSkrw vp->v_type = VREG;
651d9ac8608Spedro break;
652de3bd4b9Skrw case UDF_ICB_FILETYPE_DIRECTORY:
653d9ac8608Spedro vp->v_type = VDIR;
654d9ac8608Spedro break;
655de3bd4b9Skrw case UDF_ICB_FILETYPE_BLOCKDEVICE:
656d9ac8608Spedro vp->v_type = VBLK;
657d9ac8608Spedro break;
658de3bd4b9Skrw case UDF_ICB_FILETYPE_CHARDEVICE:
659d9ac8608Spedro vp->v_type = VCHR;
660d9ac8608Spedro break;
661de3bd4b9Skrw case UDF_ICB_FILETYPE_FIFO:
662d9ac8608Spedro vp->v_type = VFIFO;
663d9ac8608Spedro break;
664de3bd4b9Skrw case UDF_ICB_FILETYPE_SOCKET:
665d9ac8608Spedro vp->v_type = VSOCK;
666d9ac8608Spedro break;
667de3bd4b9Skrw case UDF_ICB_FILETYPE_SYMLINK:
668d9ac8608Spedro vp->v_type = VLNK;
669d9ac8608Spedro break;
670b077103dSkrw case UDF_ICB_FILETYPE_RANDOMACCESS:
671b077103dSkrw case UDF_ICB_FILETYPE_REALTIME:
672de3bd4b9Skrw case UDF_ICB_FILETYPE_UNKNOWN:
6738eb7f8cbSpedro vp->v_type = VREG;
6748eb7f8cbSpedro break;
675d9ac8608Spedro }
676d9ac8608Spedro
677b077103dSkrw /* check if this is a vnode alias */
678b077103dSkrw if ((nvp = checkalias(vp, up->u_dev, ump->um_mountp)) != NULL) {
679b077103dSkrw printf("found a vnode alias\n");
680b077103dSkrw /*
681b077103dSkrw * Discard unneeded vnode, but save its udf_node.
682b077103dSkrw * Note that the lock is carried over in the udf_node
683b077103dSkrw */
684b077103dSkrw nvp->v_data = vp->v_data;
685b077103dSkrw vp->v_data = NULL;
686dc81e71aSthib vp->v_op = &spec_vops;
687b077103dSkrw vrele(vp);
688b077103dSkrw vgone(vp);
689b077103dSkrw /*
690b077103dSkrw * Reinitialize aliased inode.
691b077103dSkrw */
692b077103dSkrw vp = nvp;
693b077103dSkrw ump->um_devvp = vp;
694b077103dSkrw }
695b077103dSkrw
696d9ac8608Spedro *vpp = vp;
697d9ac8608Spedro
698d9ac8608Spedro return (0);
699d9ac8608Spedro }
700d9ac8608Spedro
701d9ac8608Spedro struct ifid {
702d9ac8608Spedro u_short ifid_len;
703d9ac8608Spedro u_short ifid_pad;
704d9ac8608Spedro int ifid_ino;
705d9ac8608Spedro long ifid_start;
706d9ac8608Spedro };
707d9ac8608Spedro
708d9ac8608Spedro int
udf_fhtovp(struct mount * mp,struct fid * fhp,struct vnode ** vpp)709d9ac8608Spedro udf_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
710d9ac8608Spedro {
711d9ac8608Spedro struct ifid *ifhp;
712d9ac8608Spedro struct vnode *nvp;
713d9ac8608Spedro int error;
714d9ac8608Spedro
715d9ac8608Spedro ifhp = (struct ifid *)fhp;
716d9ac8608Spedro
717d9ac8608Spedro if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) {
718d9ac8608Spedro *vpp = NULLVP;
719d9ac8608Spedro return (error);
720d9ac8608Spedro }
721d9ac8608Spedro
722d9ac8608Spedro *vpp = nvp;
723d9ac8608Spedro
724d9ac8608Spedro return (0);
725d9ac8608Spedro }
726d9ac8608Spedro
727d9ac8608Spedro int
udf_vptofh(struct vnode * vp,struct fid * fhp)728d9ac8608Spedro udf_vptofh(struct vnode *vp, struct fid *fhp)
729d9ac8608Spedro {
7301af96cccSpedro struct unode *up;
731d9ac8608Spedro struct ifid *ifhp;
732d9ac8608Spedro
7331af96cccSpedro up = VTOU(vp);
734d9ac8608Spedro ifhp = (struct ifid *)fhp;
735d9ac8608Spedro ifhp->ifid_len = sizeof(struct ifid);
7361af96cccSpedro ifhp->ifid_ino = up->u_ino;
737d9ac8608Spedro
738d9ac8608Spedro return (0);
739d9ac8608Spedro }
740d9ac8608Spedro
741d9ac8608Spedro int
udf_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen,struct proc * p)742d9ac8608Spedro udf_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
743d9ac8608Spedro size_t newlen, struct proc *p)
744d9ac8608Spedro {
745d9ac8608Spedro return (EINVAL);
746d9ac8608Spedro }
747d9ac8608Spedro
748d9ac8608Spedro int
udf_checkexp(struct mount * mp,struct mbuf * nam,int * exflagsp,struct ucred ** credanonp)749d9ac8608Spedro udf_checkexp(struct mount *mp, struct mbuf *nam, int *exflagsp,
750d9ac8608Spedro struct ucred **credanonp)
751d9ac8608Spedro {
752a74002c6Spedro return (EACCES); /* For the time being */
753d9ac8608Spedro }
754d9ac8608Spedro
755a74002c6Spedro /* Handle a virtual partition map */
756a74002c6Spedro int
udf_get_vpartmap(struct umount * ump,struct part_map_virt * pmv)757170e22feSpedro udf_get_vpartmap(struct umount *ump, struct part_map_virt *pmv)
758a74002c6Spedro {
759170e22feSpedro ump->um_flags |= UDF_MNT_FIND_VAT; /* Should do more than this */
7608eb7f8cbSpedro return (0);
761a74002c6Spedro }
762a74002c6Spedro
763a74002c6Spedro /* Handle a sparable partition map */
764a74002c6Spedro int
udf_get_spartmap(struct umount * ump,struct part_map_spare * pms)765170e22feSpedro udf_get_spartmap(struct umount *ump, struct part_map_spare *pms)
766a74002c6Spedro {
767a74002c6Spedro struct buf *bp;
768a74002c6Spedro int i, error;
769a74002c6Spedro
770170e22feSpedro ump->um_stbl = malloc(letoh32(pms->st_size), M_UDFMOUNT, M_NOWAIT);
771170e22feSpedro if (ump->um_stbl == NULL)
772a74002c6Spedro return (ENOMEM);
773a74002c6Spedro
774170e22feSpedro bzero(ump->um_stbl, letoh32(pms->st_size));
775a74002c6Spedro
776a74002c6Spedro /* Calculate the number of sectors per packet */
777170e22feSpedro ump->um_psecs = letoh16(pms->packet_len) / ump->um_bsize;
778a74002c6Spedro
779170e22feSpedro error = udf_readlblks(ump, letoh32(pms->st_loc[0]),
780a74002c6Spedro letoh32(pms->st_size), &bp);
781a74002c6Spedro
782a74002c6Spedro if (error) {
783a74002c6Spedro if (bp != NULL)
784a74002c6Spedro brelse(bp);
7850e5ae731Stedu free(ump->um_stbl, M_UDFMOUNT, 0);
786a74002c6Spedro return (error); /* Failed to read sparing table */
787a74002c6Spedro }
788a74002c6Spedro
789170e22feSpedro bcopy(bp->b_data, ump->um_stbl, letoh32(pms->st_size));
790a74002c6Spedro brelse(bp);
791b077103dSkrw bp = NULL;
792a74002c6Spedro
793170e22feSpedro if (udf_checktag(&ump->um_stbl->tag, 0)) {
7940e5ae731Stedu free(ump->um_stbl, M_UDFMOUNT, 0);
795a74002c6Spedro return (EINVAL); /* Invalid sparing table found */
796a74002c6Spedro }
797a74002c6Spedro
798a74002c6Spedro /*
799a74002c6Spedro * See how many valid entries there are here. The list is
800a74002c6Spedro * supposed to be sorted, 0xfffffff0 and higher are not valid.
801a74002c6Spedro */
802170e22feSpedro for (i = 0; i < letoh16(ump->um_stbl->rt_l); i++) {
803170e22feSpedro ump->um_stbl_len = i;
804170e22feSpedro if (letoh32(ump->um_stbl->entries[i].org) >= 0xfffffff0)
805a74002c6Spedro break;
806a74002c6Spedro }
807a74002c6Spedro
808a74002c6Spedro return (0);
809a74002c6Spedro }
810a74002c6Spedro
811b077103dSkrw /* Handle a metadata partition map */
812b077103dSkrw int
udf_get_mpartmap(struct umount * ump,struct part_map_meta * pmm)813b077103dSkrw udf_get_mpartmap(struct umount *ump, struct part_map_meta *pmm)
814b077103dSkrw {
815b077103dSkrw ump->um_flags |= UDF_MNT_USES_META;
816b077103dSkrw ump->um_meta_start = pmm->meta_file_lbn;
817b077103dSkrw return (0);
818b077103dSkrw }
819de3bd4b9Skrw
820a74002c6Spedro /* Scan the partition maps */
821d9ac8608Spedro int
udf_find_partmaps(struct umount * ump,struct logvol_desc * lvd)822170e22feSpedro udf_find_partmaps(struct umount *ump, struct logvol_desc *lvd)
823d9ac8608Spedro {
824d9ac8608Spedro struct regid *pmap_id;
825d9ac8608Spedro unsigned char regid_id[UDF_REGID_ID_SIZE + 1];
826d9ac8608Spedro int i, ptype, psize, error;
82765528e40Spedro uint8_t *pmap = (uint8_t *) &lvd->maps[0];
828d9ac8608Spedro
829d9ac8608Spedro for (i = 0; i < letoh32(lvd->n_pm); i++) {
83065528e40Spedro ptype = pmap[0];
83165528e40Spedro psize = pmap[1];
83265528e40Spedro
83365528e40Spedro if (ptype != 1 && ptype != 2)
834a74002c6Spedro return (EINVAL); /* Invalid partition map type */
83565528e40Spedro
836de3bd4b9Skrw if (psize != sizeof(struct part_map_1) &&
837de3bd4b9Skrw psize != sizeof(struct part_map_2))
838a74002c6Spedro return (EINVAL); /* Invalid partition map size */
839d9ac8608Spedro
840d9ac8608Spedro if (ptype == 1) {
841de3bd4b9Skrw pmap += sizeof(struct part_map_1);
842d9ac8608Spedro continue;
843d9ac8608Spedro }
844d9ac8608Spedro
845a74002c6Spedro /* Type 2 map. Find out the details */
84665528e40Spedro pmap_id = (struct regid *) &pmap[4];
847cfe67d8fSpedro regid_id[UDF_REGID_ID_SIZE] = '\0';
848d9ac8608Spedro bcopy(&pmap_id->id[0], ®id_id[0], UDF_REGID_ID_SIZE);
849d9ac8608Spedro
850a74002c6Spedro if (!bcmp(®id_id[0], "*UDF Virtual Partition",
851a74002c6Spedro UDF_REGID_ID_SIZE))
852170e22feSpedro error = udf_get_vpartmap(ump,
853a74002c6Spedro (struct part_map_virt *) pmap);
854a74002c6Spedro else if (!bcmp(®id_id[0], "*UDF Sparable Partition",
855a74002c6Spedro UDF_REGID_ID_SIZE))
856170e22feSpedro error = udf_get_spartmap(ump,
857a74002c6Spedro (struct part_map_spare *) pmap);
858b077103dSkrw else if (!bcmp(®id_id[0], "*UDF Metadata Partition",
859b077103dSkrw UDF_REGID_ID_SIZE))
860b077103dSkrw error = udf_get_mpartmap(ump,
861b077103dSkrw (struct part_map_meta *) pmap);
862a74002c6Spedro else
863a74002c6Spedro return (EINVAL); /* Unsupported partition map */
864d9ac8608Spedro
865a74002c6Spedro if (error)
866a74002c6Spedro return (error); /* Error getting partition */
867a74002c6Spedro
868de3bd4b9Skrw pmap += sizeof(struct part_map_2);
869d9ac8608Spedro }
870d9ac8608Spedro
871d9ac8608Spedro return (0);
872d9ac8608Spedro }
873