1*03998195SJoerg Sonnenberger /*- 2*03998195SJoerg Sonnenberger * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org> 3*03998195SJoerg Sonnenberger * All rights reserved. 4*03998195SJoerg Sonnenberger * 5*03998195SJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without 6*03998195SJoerg Sonnenberger * modification, are permitted provided that the following conditions 7*03998195SJoerg Sonnenberger * are met: 8*03998195SJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright 9*03998195SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer. 10*03998195SJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright 11*03998195SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the 12*03998195SJoerg Sonnenberger * documentation and/or other materials provided with the distribution. 13*03998195SJoerg Sonnenberger * 14*03998195SJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*03998195SJoerg Sonnenberger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*03998195SJoerg Sonnenberger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*03998195SJoerg Sonnenberger * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*03998195SJoerg Sonnenberger * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*03998195SJoerg Sonnenberger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*03998195SJoerg Sonnenberger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*03998195SJoerg Sonnenberger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*03998195SJoerg Sonnenberger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*03998195SJoerg Sonnenberger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*03998195SJoerg Sonnenberger * SUCH DAMAGE. 25*03998195SJoerg Sonnenberger * 26*03998195SJoerg Sonnenberger * $FreeBSD: src/sys/fs/udf/udf_vfsops.c,v 1.16 2003/11/05 06:56:08 scottl Exp $ 27*03998195SJoerg Sonnenberger * $DragonFly: src/sys/vfs/udf/udf_vfsops.c,v 1.1 2004/03/12 22:38:15 joerg Exp $ 28*03998195SJoerg Sonnenberger */ 29*03998195SJoerg Sonnenberger 30*03998195SJoerg Sonnenberger /* udf_vfsops.c */ 31*03998195SJoerg Sonnenberger /* Implement the VFS side of things */ 32*03998195SJoerg Sonnenberger 33*03998195SJoerg Sonnenberger /* 34*03998195SJoerg Sonnenberger * Ok, here's how it goes. The UDF specs are pretty clear on how each data 35*03998195SJoerg Sonnenberger * structure is made up, but not very clear on how they relate to each other. 36*03998195SJoerg Sonnenberger * Here is the skinny... This demostrates a filesystem with one file in the 37*03998195SJoerg Sonnenberger * root directory. Subdirectories are treated just as normal files, but they 38*03998195SJoerg Sonnenberger * have File Id Descriptors of their children as their file data. As for the 39*03998195SJoerg Sonnenberger * Anchor Volume Descriptor Pointer, it can exist in two of the following three 40*03998195SJoerg Sonnenberger * places: sector 256, sector n (the max sector of the disk), or sector 41*03998195SJoerg Sonnenberger * n - 256. It's a pretty good bet that one will exist at sector 256 though. 42*03998195SJoerg Sonnenberger * One caveat is unclosed CD media. For that, sector 256 cannot be written, 43*03998195SJoerg Sonnenberger * so the Anchor Volume Descriptor Pointer can exist at sector 512 until the 44*03998195SJoerg Sonnenberger * media is closed. 45*03998195SJoerg Sonnenberger * 46*03998195SJoerg Sonnenberger * Sector: 47*03998195SJoerg Sonnenberger * 256: 48*03998195SJoerg Sonnenberger * n: Anchor Volume Descriptor Pointer 49*03998195SJoerg Sonnenberger * n - 256: | 50*03998195SJoerg Sonnenberger * | 51*03998195SJoerg Sonnenberger * |-->Main Volume Descriptor Sequence 52*03998195SJoerg Sonnenberger * | | 53*03998195SJoerg Sonnenberger * | | 54*03998195SJoerg Sonnenberger * | |-->Logical Volume Descriptor 55*03998195SJoerg Sonnenberger * | | 56*03998195SJoerg Sonnenberger * |-->Partition Descriptor | 57*03998195SJoerg Sonnenberger * | | 58*03998195SJoerg Sonnenberger * | | 59*03998195SJoerg Sonnenberger * |-->Fileset Descriptor 60*03998195SJoerg Sonnenberger * | 61*03998195SJoerg Sonnenberger * | 62*03998195SJoerg Sonnenberger * |-->Root Dir File Entry 63*03998195SJoerg Sonnenberger * | 64*03998195SJoerg Sonnenberger * | 65*03998195SJoerg Sonnenberger * |-->File data: 66*03998195SJoerg Sonnenberger * File Id Descriptor 67*03998195SJoerg Sonnenberger * | 68*03998195SJoerg Sonnenberger * | 69*03998195SJoerg Sonnenberger * |-->File Entry 70*03998195SJoerg Sonnenberger * | 71*03998195SJoerg Sonnenberger * | 72*03998195SJoerg Sonnenberger * |-->File data 73*03998195SJoerg Sonnenberger */ 74*03998195SJoerg Sonnenberger 75*03998195SJoerg Sonnenberger #include <sys/types.h> 76*03998195SJoerg Sonnenberger #include <sys/param.h> 77*03998195SJoerg Sonnenberger #include <sys/systm.h> 78*03998195SJoerg Sonnenberger #include <sys/uio.h> 79*03998195SJoerg Sonnenberger #include <sys/buf.h> 80*03998195SJoerg Sonnenberger #include <sys/conf.h> 81*03998195SJoerg Sonnenberger #include <sys/dirent.h> 82*03998195SJoerg Sonnenberger #include <sys/fcntl.h> 83*03998195SJoerg Sonnenberger #include <sys/module.h> 84*03998195SJoerg Sonnenberger #include <sys/kernel.h> 85*03998195SJoerg Sonnenberger #include <sys/malloc.h> 86*03998195SJoerg Sonnenberger #include <sys/mount.h> 87*03998195SJoerg Sonnenberger #include <sys/namei.h> 88*03998195SJoerg Sonnenberger #include <sys/proc.h> 89*03998195SJoerg Sonnenberger #include <sys/queue.h> 90*03998195SJoerg Sonnenberger #include <sys/vnode.h> 91*03998195SJoerg Sonnenberger 92*03998195SJoerg Sonnenberger #include <vfs/udf/ecma167-udf.h> 93*03998195SJoerg Sonnenberger #include <vfs/udf/osta.h> 94*03998195SJoerg Sonnenberger #include <vfs/udf/udf.h> 95*03998195SJoerg Sonnenberger #include <vfs/udf/udf_mount.h> 96*03998195SJoerg Sonnenberger 97*03998195SJoerg Sonnenberger MALLOC_DEFINE(M_UDFNODE, "UDF node", "UDF node structure"); 98*03998195SJoerg Sonnenberger MALLOC_DEFINE(M_UDFMOUNT, "UDF mount", "UDF mount structure"); 99*03998195SJoerg Sonnenberger MALLOC_DEFINE(M_UDFFENTRY, "UDF fentry", "UDF file entry structure"); 100*03998195SJoerg Sonnenberger 101*03998195SJoerg Sonnenberger static int udf_mount(struct mount *, char *, caddr_t, struct nameidata *, 102*03998195SJoerg Sonnenberger struct thread *); 103*03998195SJoerg Sonnenberger static int udf_unmount(struct mount *, int, struct thread *); 104*03998195SJoerg Sonnenberger static int udf_root(struct mount *, struct vnode **); 105*03998195SJoerg Sonnenberger static int udf_statfs(struct mount *, struct statfs *, struct thread *); 106*03998195SJoerg Sonnenberger static int udf_fhtovp(struct mount *, struct fid *, struct vnode **); 107*03998195SJoerg Sonnenberger static int udf_vptofh(struct vnode *, struct fid *); 108*03998195SJoerg Sonnenberger 109*03998195SJoerg Sonnenberger static int udf_find_partmaps(struct udf_mnt *, struct logvol_desc *); 110*03998195SJoerg Sonnenberger 111*03998195SJoerg Sonnenberger static struct vfsops udf_vfsops = { 112*03998195SJoerg Sonnenberger udf_mount, 113*03998195SJoerg Sonnenberger vfs_stdstart, 114*03998195SJoerg Sonnenberger udf_unmount, 115*03998195SJoerg Sonnenberger udf_root, 116*03998195SJoerg Sonnenberger vfs_stdquotactl, 117*03998195SJoerg Sonnenberger udf_statfs, 118*03998195SJoerg Sonnenberger vfs_stdsync, 119*03998195SJoerg Sonnenberger udf_vget, 120*03998195SJoerg Sonnenberger udf_fhtovp, 121*03998195SJoerg Sonnenberger vfs_stdcheckexp, 122*03998195SJoerg Sonnenberger udf_vptofh, 123*03998195SJoerg Sonnenberger vfs_stdinit, 124*03998195SJoerg Sonnenberger vfs_stduninit, 125*03998195SJoerg Sonnenberger vfs_stdextattrctl, 126*03998195SJoerg Sonnenberger }; 127*03998195SJoerg Sonnenberger VFS_SET(udf_vfsops, udf, VFCF_READONLY); 128*03998195SJoerg Sonnenberger 129*03998195SJoerg Sonnenberger MODULE_VERSION(udf, 1); 130*03998195SJoerg Sonnenberger 131*03998195SJoerg Sonnenberger static int udf_mountfs(struct vnode *, struct mount *, struct thread *); 132*03998195SJoerg Sonnenberger 133*03998195SJoerg Sonnenberger static int 134*03998195SJoerg Sonnenberger udf_mount(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, 135*03998195SJoerg Sonnenberger struct thread *td) 136*03998195SJoerg Sonnenberger { 137*03998195SJoerg Sonnenberger struct vnode *devvp; /* vnode of the mount device */ 138*03998195SJoerg Sonnenberger struct udf_args args; 139*03998195SJoerg Sonnenberger struct udf_mnt *imp = 0; 140*03998195SJoerg Sonnenberger size_t size; 141*03998195SJoerg Sonnenberger int error; 142*03998195SJoerg Sonnenberger 143*03998195SJoerg Sonnenberger if ((mp->mnt_flag & MNT_RDONLY) == 0) 144*03998195SJoerg Sonnenberger return (EROFS); 145*03998195SJoerg Sonnenberger 146*03998195SJoerg Sonnenberger /* 147*03998195SJoerg Sonnenberger * No root filesystem support. Probably not a big deal, since the 148*03998195SJoerg Sonnenberger * bootloader doesn't understand UDF. 149*03998195SJoerg Sonnenberger */ 150*03998195SJoerg Sonnenberger if (mp->mnt_flag & MNT_ROOTFS) 151*03998195SJoerg Sonnenberger return (ENOTSUP); 152*03998195SJoerg Sonnenberger 153*03998195SJoerg Sonnenberger if ((error = copyin(data, (caddr_t)&args, sizeof(struct udf_args)))) 154*03998195SJoerg Sonnenberger return(error); 155*03998195SJoerg Sonnenberger 156*03998195SJoerg Sonnenberger if (mp->mnt_flag & MNT_UPDATE) { 157*03998195SJoerg Sonnenberger imp = VFSTOUDFFS(mp); 158*03998195SJoerg Sonnenberger if (args.fspec == NULL) 159*03998195SJoerg Sonnenberger return(vfs_export(mp, &imp->im_export, &args.export)); 160*03998195SJoerg Sonnenberger } 161*03998195SJoerg Sonnenberger 162*03998195SJoerg Sonnenberger /* Check that the mount device exists */ 163*03998195SJoerg Sonnenberger NDINIT(ndp, NAMEI_LOOKUP, CNP_FOLLOW, UIO_USERSPACE, args.fspec, td); 164*03998195SJoerg Sonnenberger if ((error = namei(ndp))) 165*03998195SJoerg Sonnenberger return(error); 166*03998195SJoerg Sonnenberger NDFREE(ndp, NDF_ONLY_PNBUF); 167*03998195SJoerg Sonnenberger devvp = ndp->ni_vp; 168*03998195SJoerg Sonnenberger 169*03998195SJoerg Sonnenberger if (vn_isdisk(devvp, &error) == 0) { 170*03998195SJoerg Sonnenberger vrele(devvp); 171*03998195SJoerg Sonnenberger return(error); 172*03998195SJoerg Sonnenberger } 173*03998195SJoerg Sonnenberger 174*03998195SJoerg Sonnenberger /* Check the access rights on the mount device */ 175*03998195SJoerg Sonnenberger vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); 176*03998195SJoerg Sonnenberger error = VOP_ACCESS(devvp, VREAD, td->td_proc->p_ucred, td); 177*03998195SJoerg Sonnenberger if (error) 178*03998195SJoerg Sonnenberger error = suser(td); 179*03998195SJoerg Sonnenberger if (error) { 180*03998195SJoerg Sonnenberger vput(devvp); 181*03998195SJoerg Sonnenberger return(error); 182*03998195SJoerg Sonnenberger } 183*03998195SJoerg Sonnenberger VOP_UNLOCK(devvp, NULL, 0, td); 184*03998195SJoerg Sonnenberger 185*03998195SJoerg Sonnenberger if ((error = udf_mountfs(devvp, mp, td))) { 186*03998195SJoerg Sonnenberger vrele(devvp); 187*03998195SJoerg Sonnenberger return(error); 188*03998195SJoerg Sonnenberger } 189*03998195SJoerg Sonnenberger 190*03998195SJoerg Sonnenberger imp = VFSTOUDFFS(mp); 191*03998195SJoerg Sonnenberger 192*03998195SJoerg Sonnenberger imp->im_flags = args.flags; 193*03998195SJoerg Sonnenberger 194*03998195SJoerg Sonnenberger copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 195*03998195SJoerg Sonnenberger bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 196*03998195SJoerg Sonnenberger copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 197*03998195SJoerg Sonnenberger bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 198*03998195SJoerg Sonnenberger udf_statfs(mp, &mp->mnt_stat, td); 199*03998195SJoerg Sonnenberger return(0); 200*03998195SJoerg Sonnenberger }; 201*03998195SJoerg Sonnenberger 202*03998195SJoerg Sonnenberger /* 203*03998195SJoerg Sonnenberger * Check the descriptor tag for both the correct id and correct checksum. 204*03998195SJoerg Sonnenberger * Return zero if all is good, EINVAL if not. 205*03998195SJoerg Sonnenberger */ 206*03998195SJoerg Sonnenberger int 207*03998195SJoerg Sonnenberger udf_checktag(struct desc_tag *tag, uint16_t id) 208*03998195SJoerg Sonnenberger { 209*03998195SJoerg Sonnenberger uint8_t *itag; 210*03998195SJoerg Sonnenberger uint8_t i, cksum = 0; 211*03998195SJoerg Sonnenberger 212*03998195SJoerg Sonnenberger itag = (uint8_t *)tag; 213*03998195SJoerg Sonnenberger 214*03998195SJoerg Sonnenberger if (tag->id != id) 215*03998195SJoerg Sonnenberger return(EINVAL); 216*03998195SJoerg Sonnenberger 217*03998195SJoerg Sonnenberger for (i = 0; i < 15; i++) 218*03998195SJoerg Sonnenberger cksum = cksum + itag[i]; 219*03998195SJoerg Sonnenberger cksum = cksum - itag[4]; 220*03998195SJoerg Sonnenberger 221*03998195SJoerg Sonnenberger if (cksum == tag->cksum) 222*03998195SJoerg Sonnenberger return(0); 223*03998195SJoerg Sonnenberger 224*03998195SJoerg Sonnenberger return(EINVAL); 225*03998195SJoerg Sonnenberger } 226*03998195SJoerg Sonnenberger 227*03998195SJoerg Sonnenberger static int 228*03998195SJoerg Sonnenberger udf_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td) { 229*03998195SJoerg Sonnenberger struct buf *bp = NULL; 230*03998195SJoerg Sonnenberger struct anchor_vdp avdp; 231*03998195SJoerg Sonnenberger struct udf_mnt *udfmp = NULL; 232*03998195SJoerg Sonnenberger struct part_desc *pd; 233*03998195SJoerg Sonnenberger struct logvol_desc *lvd; 234*03998195SJoerg Sonnenberger struct fileset_desc *fsd; 235*03998195SJoerg Sonnenberger struct file_entry *root_fentry; 236*03998195SJoerg Sonnenberger uint32_t sector, size, mvds_start, mvds_end; 237*03998195SJoerg Sonnenberger uint32_t fsd_offset = 0; 238*03998195SJoerg Sonnenberger uint16_t part_num = 0, fsd_part = 0; 239*03998195SJoerg Sonnenberger int error = EINVAL, needclose = 0; 240*03998195SJoerg Sonnenberger int logvol_found = 0, part_found = 0, fsd_found = 0; 241*03998195SJoerg Sonnenberger int bsize; 242*03998195SJoerg Sonnenberger 243*03998195SJoerg Sonnenberger /* 244*03998195SJoerg Sonnenberger * Disallow multiple mounts of the same device. Flush the buffer 245*03998195SJoerg Sonnenberger * cache for the device. 246*03998195SJoerg Sonnenberger */ 247*03998195SJoerg Sonnenberger if ((error = vfs_mountedon(devvp))) 248*03998195SJoerg Sonnenberger return(error); 249*03998195SJoerg Sonnenberger if (vcount(devvp) > 1) 250*03998195SJoerg Sonnenberger return(EBUSY); 251*03998195SJoerg Sonnenberger if ((error = vinvalbuf(devvp, V_SAVE, td, 0, 0))) 252*03998195SJoerg Sonnenberger return(error); 253*03998195SJoerg Sonnenberger 254*03998195SJoerg Sonnenberger vn_lock(devvp, NULL, LK_EXCLUSIVE | LK_RETRY, td); 255*03998195SJoerg Sonnenberger error = VOP_OPEN(devvp, FREAD, FSCRED, td); 256*03998195SJoerg Sonnenberger VOP_UNLOCK(devvp, NULL, 0, td); 257*03998195SJoerg Sonnenberger if (error) 258*03998195SJoerg Sonnenberger return(error); 259*03998195SJoerg Sonnenberger needclose = 1; 260*03998195SJoerg Sonnenberger 261*03998195SJoerg Sonnenberger udfmp = malloc(sizeof(*udfmp), M_UDFMOUNT, M_WAITOK | M_ZERO); 262*03998195SJoerg Sonnenberger 263*03998195SJoerg Sonnenberger mp->mnt_data = (qaddr_t)udfmp; 264*03998195SJoerg Sonnenberger mp->mnt_stat.f_fsid.val[0] = dev2udev(devvp->v_rdev); 265*03998195SJoerg Sonnenberger mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 266*03998195SJoerg Sonnenberger mp->mnt_maxsymlinklen = 0; 267*03998195SJoerg Sonnenberger mp->mnt_flag |= MNT_LOCAL; 268*03998195SJoerg Sonnenberger udfmp->im_mountp = mp; 269*03998195SJoerg Sonnenberger udfmp->im_dev = devvp->v_rdev; 270*03998195SJoerg Sonnenberger udfmp->im_devvp = devvp; 271*03998195SJoerg Sonnenberger 272*03998195SJoerg Sonnenberger bsize = 2048; /* XXX Should probe the media for it's size */ 273*03998195SJoerg Sonnenberger 274*03998195SJoerg Sonnenberger /* 275*03998195SJoerg Sonnenberger * Get the Anchor Volume Descriptor Pointer from sector 256. 276*03998195SJoerg Sonnenberger * XXX Should also check sector n - 256, n, and 512. 277*03998195SJoerg Sonnenberger */ 278*03998195SJoerg Sonnenberger sector = 256; 279*03998195SJoerg Sonnenberger if ((error = bread(devvp, sector * btodb(bsize), bsize, &bp)) != 0) 280*03998195SJoerg Sonnenberger goto bail; 281*03998195SJoerg Sonnenberger if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR))) 282*03998195SJoerg Sonnenberger goto bail; 283*03998195SJoerg Sonnenberger 284*03998195SJoerg Sonnenberger bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp)); 285*03998195SJoerg Sonnenberger brelse(bp); 286*03998195SJoerg Sonnenberger bp = NULL; 287*03998195SJoerg Sonnenberger 288*03998195SJoerg Sonnenberger /* 289*03998195SJoerg Sonnenberger * Extract the Partition Descriptor and Logical Volume Descriptor 290*03998195SJoerg Sonnenberger * from the Volume Descriptor Sequence. 291*03998195SJoerg Sonnenberger * XXX Should we care about the partition type right now? 292*03998195SJoerg Sonnenberger * XXX What about multiple partitions? 293*03998195SJoerg Sonnenberger */ 294*03998195SJoerg Sonnenberger mvds_start = avdp.main_vds_ex.loc; 295*03998195SJoerg Sonnenberger mvds_end = mvds_start + (avdp.main_vds_ex.len - 1) / bsize; 296*03998195SJoerg Sonnenberger for (sector = mvds_start; sector < mvds_end; sector++) { 297*03998195SJoerg Sonnenberger if ((error = bread(devvp, sector * btodb(bsize), bsize, 298*03998195SJoerg Sonnenberger &bp)) != 0) { 299*03998195SJoerg Sonnenberger printf("Can't read sector %d of VDS\n", sector); 300*03998195SJoerg Sonnenberger goto bail; 301*03998195SJoerg Sonnenberger } 302*03998195SJoerg Sonnenberger lvd = (struct logvol_desc *)bp->b_data; 303*03998195SJoerg Sonnenberger if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) { 304*03998195SJoerg Sonnenberger udfmp->bsize = lvd->lb_size; 305*03998195SJoerg Sonnenberger udfmp->bmask = udfmp->bsize - 1; 306*03998195SJoerg Sonnenberger udfmp->bshift = ffs(udfmp->bsize) - 1; 307*03998195SJoerg Sonnenberger fsd_part = lvd->_lvd_use.fsd_loc.loc.part_num; 308*03998195SJoerg Sonnenberger fsd_offset = lvd->_lvd_use.fsd_loc.loc.lb_num; 309*03998195SJoerg Sonnenberger if (udf_find_partmaps(udfmp, lvd)) 310*03998195SJoerg Sonnenberger break; 311*03998195SJoerg Sonnenberger logvol_found = 1; 312*03998195SJoerg Sonnenberger } 313*03998195SJoerg Sonnenberger pd = (struct part_desc *)bp->b_data; 314*03998195SJoerg Sonnenberger if (!udf_checktag(&pd->tag, TAGID_PARTITION)) { 315*03998195SJoerg Sonnenberger part_found = 1; 316*03998195SJoerg Sonnenberger part_num = pd->part_num; 317*03998195SJoerg Sonnenberger udfmp->part_len = pd->part_len; 318*03998195SJoerg Sonnenberger udfmp->part_start = pd->start_loc; 319*03998195SJoerg Sonnenberger } 320*03998195SJoerg Sonnenberger 321*03998195SJoerg Sonnenberger brelse(bp); 322*03998195SJoerg Sonnenberger bp = NULL; 323*03998195SJoerg Sonnenberger if ((part_found) && (logvol_found)) 324*03998195SJoerg Sonnenberger break; 325*03998195SJoerg Sonnenberger } 326*03998195SJoerg Sonnenberger 327*03998195SJoerg Sonnenberger if (!part_found || !logvol_found) { 328*03998195SJoerg Sonnenberger error = EINVAL; 329*03998195SJoerg Sonnenberger goto bail; 330*03998195SJoerg Sonnenberger } 331*03998195SJoerg Sonnenberger 332*03998195SJoerg Sonnenberger if (fsd_part != part_num) { 333*03998195SJoerg Sonnenberger printf("FSD does not lie within the partition!\n"); 334*03998195SJoerg Sonnenberger error = EINVAL; 335*03998195SJoerg Sonnenberger goto bail; 336*03998195SJoerg Sonnenberger } 337*03998195SJoerg Sonnenberger 338*03998195SJoerg Sonnenberger 339*03998195SJoerg Sonnenberger /* 340*03998195SJoerg Sonnenberger * Grab the Fileset Descriptor 341*03998195SJoerg Sonnenberger * Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing 342*03998195SJoerg Sonnenberger * me in the right direction here. 343*03998195SJoerg Sonnenberger */ 344*03998195SJoerg Sonnenberger sector = udfmp->part_start + fsd_offset; 345*03998195SJoerg Sonnenberger if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) { 346*03998195SJoerg Sonnenberger printf("Cannot read sector %d of FSD\n", sector); 347*03998195SJoerg Sonnenberger goto bail; 348*03998195SJoerg Sonnenberger } 349*03998195SJoerg Sonnenberger fsd = (struct fileset_desc *)bp->b_data; 350*03998195SJoerg Sonnenberger if (!udf_checktag(&fsd->tag, TAGID_FSD)) { 351*03998195SJoerg Sonnenberger fsd_found = 1; 352*03998195SJoerg Sonnenberger bcopy(&fsd->rootdir_icb, &udfmp->root_icb, 353*03998195SJoerg Sonnenberger sizeof(struct long_ad)); 354*03998195SJoerg Sonnenberger } 355*03998195SJoerg Sonnenberger 356*03998195SJoerg Sonnenberger brelse(bp); 357*03998195SJoerg Sonnenberger bp = NULL; 358*03998195SJoerg Sonnenberger 359*03998195SJoerg Sonnenberger if (!fsd_found) { 360*03998195SJoerg Sonnenberger printf("Couldn't find the fsd\n"); 361*03998195SJoerg Sonnenberger error = EINVAL; 362*03998195SJoerg Sonnenberger goto bail; 363*03998195SJoerg Sonnenberger } 364*03998195SJoerg Sonnenberger 365*03998195SJoerg Sonnenberger /* 366*03998195SJoerg Sonnenberger * Find the file entry for the root directory. 367*03998195SJoerg Sonnenberger */ 368*03998195SJoerg Sonnenberger sector = udfmp->root_icb.loc.lb_num + udfmp->part_start; 369*03998195SJoerg Sonnenberger size = udfmp->root_icb.len; 370*03998195SJoerg Sonnenberger if ((error = udf_readlblks(udfmp, sector, size, &bp)) != 0) { 371*03998195SJoerg Sonnenberger printf("Cannot read sector %d\n", sector); 372*03998195SJoerg Sonnenberger goto bail; 373*03998195SJoerg Sonnenberger } 374*03998195SJoerg Sonnenberger 375*03998195SJoerg Sonnenberger root_fentry = (struct file_entry *)bp->b_data; 376*03998195SJoerg Sonnenberger if ((error = udf_checktag(&root_fentry->tag, TAGID_FENTRY))) { 377*03998195SJoerg Sonnenberger printf("Invalid root file entry!\n"); 378*03998195SJoerg Sonnenberger goto bail; 379*03998195SJoerg Sonnenberger } 380*03998195SJoerg Sonnenberger 381*03998195SJoerg Sonnenberger brelse(bp); 382*03998195SJoerg Sonnenberger bp = NULL; 383*03998195SJoerg Sonnenberger 384*03998195SJoerg Sonnenberger lwkt_token_init(&udfmp->hash_token); 385*03998195SJoerg Sonnenberger udfmp->hashtbl = phashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, &udfmp->hashsz); 386*03998195SJoerg Sonnenberger 387*03998195SJoerg Sonnenberger return(0); 388*03998195SJoerg Sonnenberger 389*03998195SJoerg Sonnenberger bail: 390*03998195SJoerg Sonnenberger if (udfmp != NULL) 391*03998195SJoerg Sonnenberger free(udfmp, M_UDFMOUNT); 392*03998195SJoerg Sonnenberger if (bp != NULL) 393*03998195SJoerg Sonnenberger brelse(bp); 394*03998195SJoerg Sonnenberger if (needclose) 395*03998195SJoerg Sonnenberger VOP_CLOSE(devvp, FREAD, td); 396*03998195SJoerg Sonnenberger return(error); 397*03998195SJoerg Sonnenberger }; 398*03998195SJoerg Sonnenberger 399*03998195SJoerg Sonnenberger static int 400*03998195SJoerg Sonnenberger udf_unmount(struct mount *mp, int mntflags, struct thread *td) 401*03998195SJoerg Sonnenberger { 402*03998195SJoerg Sonnenberger struct udf_mnt *udfmp; 403*03998195SJoerg Sonnenberger int error, flags = 0; 404*03998195SJoerg Sonnenberger 405*03998195SJoerg Sonnenberger udfmp = VFSTOUDFFS(mp); 406*03998195SJoerg Sonnenberger 407*03998195SJoerg Sonnenberger if (mntflags & MNT_FORCE) 408*03998195SJoerg Sonnenberger flags |= FORCECLOSE; 409*03998195SJoerg Sonnenberger 410*03998195SJoerg Sonnenberger if ((error = vflush(mp, 0, flags))) 411*03998195SJoerg Sonnenberger return (error); 412*03998195SJoerg Sonnenberger 413*03998195SJoerg Sonnenberger udfmp->im_devvp->v_specmountpoint = NULL; 414*03998195SJoerg Sonnenberger error = VOP_CLOSE(udfmp->im_devvp, FREAD, td); 415*03998195SJoerg Sonnenberger vrele(udfmp->im_devvp); 416*03998195SJoerg Sonnenberger 417*03998195SJoerg Sonnenberger if (udfmp->s_table) 418*03998195SJoerg Sonnenberger free(udfmp->s_table, M_UDFMOUNT); 419*03998195SJoerg Sonnenberger if (udfmp->hashtbl) 420*03998195SJoerg Sonnenberger free(udfmp->hashtbl, M_UDFMOUNT); 421*03998195SJoerg Sonnenberger free(udfmp, M_UDFMOUNT); 422*03998195SJoerg Sonnenberger 423*03998195SJoerg Sonnenberger mp->mnt_data = (qaddr_t)0; 424*03998195SJoerg Sonnenberger mp->mnt_flag &= ~MNT_LOCAL; 425*03998195SJoerg Sonnenberger 426*03998195SJoerg Sonnenberger return (error); 427*03998195SJoerg Sonnenberger } 428*03998195SJoerg Sonnenberger 429*03998195SJoerg Sonnenberger static int 430*03998195SJoerg Sonnenberger udf_root(struct mount *mp, struct vnode **vpp) 431*03998195SJoerg Sonnenberger { 432*03998195SJoerg Sonnenberger struct udf_mnt *udfmp; 433*03998195SJoerg Sonnenberger struct vnode *vp; 434*03998195SJoerg Sonnenberger ino_t id; 435*03998195SJoerg Sonnenberger int error; 436*03998195SJoerg Sonnenberger 437*03998195SJoerg Sonnenberger udfmp = VFSTOUDFFS(mp); 438*03998195SJoerg Sonnenberger 439*03998195SJoerg Sonnenberger id = udf_getid(&udfmp->root_icb); 440*03998195SJoerg Sonnenberger 441*03998195SJoerg Sonnenberger error = udf_vget(mp, id, vpp); 442*03998195SJoerg Sonnenberger if (error) 443*03998195SJoerg Sonnenberger return(error); 444*03998195SJoerg Sonnenberger 445*03998195SJoerg Sonnenberger vp = *vpp; 446*03998195SJoerg Sonnenberger vp->v_flag |= VROOT; 447*03998195SJoerg Sonnenberger udfmp->root_vp = vp; 448*03998195SJoerg Sonnenberger 449*03998195SJoerg Sonnenberger return(0); 450*03998195SJoerg Sonnenberger } 451*03998195SJoerg Sonnenberger 452*03998195SJoerg Sonnenberger static int 453*03998195SJoerg Sonnenberger udf_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) 454*03998195SJoerg Sonnenberger { 455*03998195SJoerg Sonnenberger struct udf_mnt *udfmp; 456*03998195SJoerg Sonnenberger 457*03998195SJoerg Sonnenberger udfmp = VFSTOUDFFS(mp); 458*03998195SJoerg Sonnenberger 459*03998195SJoerg Sonnenberger sbp->f_bsize = udfmp->bsize; 460*03998195SJoerg Sonnenberger sbp->f_iosize = udfmp->bsize; 461*03998195SJoerg Sonnenberger sbp->f_blocks = udfmp->part_len; 462*03998195SJoerg Sonnenberger sbp->f_bfree = 0; 463*03998195SJoerg Sonnenberger sbp->f_bavail = 0; 464*03998195SJoerg Sonnenberger sbp->f_files = 0; 465*03998195SJoerg Sonnenberger sbp->f_ffree = 0; 466*03998195SJoerg Sonnenberger if (sbp != &mp->mnt_stat) { 467*03998195SJoerg Sonnenberger sbp->f_type = mp->mnt_vfc->vfc_typenum; 468*03998195SJoerg Sonnenberger bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 469*03998195SJoerg Sonnenberger bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 470*03998195SJoerg Sonnenberger } 471*03998195SJoerg Sonnenberger 472*03998195SJoerg Sonnenberger return(0); 473*03998195SJoerg Sonnenberger } 474*03998195SJoerg Sonnenberger 475*03998195SJoerg Sonnenberger int 476*03998195SJoerg Sonnenberger udf_vget(struct mount *mp, ino_t ino, struct vnode **vpp) 477*03998195SJoerg Sonnenberger { 478*03998195SJoerg Sonnenberger struct buf *bp; 479*03998195SJoerg Sonnenberger struct vnode *devvp; 480*03998195SJoerg Sonnenberger struct udf_mnt *udfmp; 481*03998195SJoerg Sonnenberger struct thread *td; 482*03998195SJoerg Sonnenberger struct vnode *vp; 483*03998195SJoerg Sonnenberger struct udf_node *unode; 484*03998195SJoerg Sonnenberger struct file_entry *fe; 485*03998195SJoerg Sonnenberger int error, sector, size; 486*03998195SJoerg Sonnenberger 487*03998195SJoerg Sonnenberger td = curthread; 488*03998195SJoerg Sonnenberger udfmp = VFSTOUDFFS(mp); 489*03998195SJoerg Sonnenberger 490*03998195SJoerg Sonnenberger /* See if we already have this in the cache */ 491*03998195SJoerg Sonnenberger if ((error = udf_hashlookup(udfmp, ino, vpp)) != 0) 492*03998195SJoerg Sonnenberger return(error); 493*03998195SJoerg Sonnenberger if (*vpp != NULL) { 494*03998195SJoerg Sonnenberger return(0); 495*03998195SJoerg Sonnenberger } 496*03998195SJoerg Sonnenberger 497*03998195SJoerg Sonnenberger /* 498*03998195SJoerg Sonnenberger * Allocate memory and check the tag id's before grabbing a new 499*03998195SJoerg Sonnenberger * vnode, since it's hard to roll back if there is a problem. 500*03998195SJoerg Sonnenberger */ 501*03998195SJoerg Sonnenberger unode = malloc(sizeof(*unode), M_UDFNODE, M_WAITOK | M_ZERO); 502*03998195SJoerg Sonnenberger 503*03998195SJoerg Sonnenberger /* 504*03998195SJoerg Sonnenberger * Copy in the file entry. Per the spec, the size can only be 1 block. 505*03998195SJoerg Sonnenberger */ 506*03998195SJoerg Sonnenberger sector = ino + udfmp->part_start; 507*03998195SJoerg Sonnenberger devvp = udfmp->im_devvp; 508*03998195SJoerg Sonnenberger if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) { 509*03998195SJoerg Sonnenberger printf("Cannot read sector %d\n", sector); 510*03998195SJoerg Sonnenberger free(unode, M_UDFNODE); 511*03998195SJoerg Sonnenberger return(error); 512*03998195SJoerg Sonnenberger } 513*03998195SJoerg Sonnenberger 514*03998195SJoerg Sonnenberger fe = (struct file_entry *)bp->b_data; 515*03998195SJoerg Sonnenberger if (udf_checktag(&fe->tag, TAGID_FENTRY)) { 516*03998195SJoerg Sonnenberger printf("Invalid file entry!\n"); 517*03998195SJoerg Sonnenberger free(unode, M_UDFNODE); 518*03998195SJoerg Sonnenberger brelse(bp); 519*03998195SJoerg Sonnenberger return(ENOMEM); 520*03998195SJoerg Sonnenberger } 521*03998195SJoerg Sonnenberger size = UDF_FENTRY_SIZE + fe->l_ea + fe->l_ad; 522*03998195SJoerg Sonnenberger unode->fentry = malloc(size, M_UDFFENTRY, M_WAITOK | M_ZERO); 523*03998195SJoerg Sonnenberger 524*03998195SJoerg Sonnenberger bcopy(bp->b_data, unode->fentry, size); 525*03998195SJoerg Sonnenberger 526*03998195SJoerg Sonnenberger brelse(bp); 527*03998195SJoerg Sonnenberger bp = NULL; 528*03998195SJoerg Sonnenberger 529*03998195SJoerg Sonnenberger if ((error = udf_allocv(mp, &vp))) { 530*03998195SJoerg Sonnenberger printf("Error from udf_allocv\n"); 531*03998195SJoerg Sonnenberger free(unode, M_UDFNODE); 532*03998195SJoerg Sonnenberger return(error); 533*03998195SJoerg Sonnenberger } 534*03998195SJoerg Sonnenberger 535*03998195SJoerg Sonnenberger unode->i_vnode = vp; 536*03998195SJoerg Sonnenberger unode->hash_id = ino; 537*03998195SJoerg Sonnenberger unode->i_devvp = udfmp->im_devvp; 538*03998195SJoerg Sonnenberger unode->i_dev = udfmp->im_dev; 539*03998195SJoerg Sonnenberger unode->udfmp = udfmp; 540*03998195SJoerg Sonnenberger vp->v_data = unode; 541*03998195SJoerg Sonnenberger VREF(udfmp->im_devvp); 542*03998195SJoerg Sonnenberger udf_hashins(unode); 543*03998195SJoerg Sonnenberger 544*03998195SJoerg Sonnenberger switch (unode->fentry->icbtag.file_type) { 545*03998195SJoerg Sonnenberger default: 546*03998195SJoerg Sonnenberger vp->v_type = VBAD; 547*03998195SJoerg Sonnenberger break; 548*03998195SJoerg Sonnenberger case 4: 549*03998195SJoerg Sonnenberger vp->v_type = VDIR; 550*03998195SJoerg Sonnenberger break; 551*03998195SJoerg Sonnenberger case 5: 552*03998195SJoerg Sonnenberger vp->v_type = VREG; 553*03998195SJoerg Sonnenberger break; 554*03998195SJoerg Sonnenberger case 6: 555*03998195SJoerg Sonnenberger vp->v_type = VBLK; 556*03998195SJoerg Sonnenberger break; 557*03998195SJoerg Sonnenberger case 7: 558*03998195SJoerg Sonnenberger vp->v_type = VCHR; 559*03998195SJoerg Sonnenberger break; 560*03998195SJoerg Sonnenberger case 9: 561*03998195SJoerg Sonnenberger vp->v_type = VFIFO; 562*03998195SJoerg Sonnenberger break; 563*03998195SJoerg Sonnenberger case 10: 564*03998195SJoerg Sonnenberger vp->v_type = VSOCK; 565*03998195SJoerg Sonnenberger break; 566*03998195SJoerg Sonnenberger case 12: 567*03998195SJoerg Sonnenberger vp->v_type = VLNK; 568*03998195SJoerg Sonnenberger break; 569*03998195SJoerg Sonnenberger } 570*03998195SJoerg Sonnenberger *vpp = vp; 571*03998195SJoerg Sonnenberger 572*03998195SJoerg Sonnenberger return(0); 573*03998195SJoerg Sonnenberger } 574*03998195SJoerg Sonnenberger 575*03998195SJoerg Sonnenberger struct ifid { 576*03998195SJoerg Sonnenberger u_short ifid_len; 577*03998195SJoerg Sonnenberger u_short ifid_pad; 578*03998195SJoerg Sonnenberger int ifid_ino; 579*03998195SJoerg Sonnenberger long ifid_start; 580*03998195SJoerg Sonnenberger }; 581*03998195SJoerg Sonnenberger 582*03998195SJoerg Sonnenberger static int 583*03998195SJoerg Sonnenberger udf_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) 584*03998195SJoerg Sonnenberger { 585*03998195SJoerg Sonnenberger struct ifid *ifhp; 586*03998195SJoerg Sonnenberger struct vnode *nvp; 587*03998195SJoerg Sonnenberger int error; 588*03998195SJoerg Sonnenberger 589*03998195SJoerg Sonnenberger ifhp = (struct ifid *)fhp; 590*03998195SJoerg Sonnenberger 591*03998195SJoerg Sonnenberger if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) { 592*03998195SJoerg Sonnenberger *vpp = NULLVP; 593*03998195SJoerg Sonnenberger return(error); 594*03998195SJoerg Sonnenberger } 595*03998195SJoerg Sonnenberger 596*03998195SJoerg Sonnenberger *vpp = nvp; 597*03998195SJoerg Sonnenberger return(0); 598*03998195SJoerg Sonnenberger } 599*03998195SJoerg Sonnenberger 600*03998195SJoerg Sonnenberger static int 601*03998195SJoerg Sonnenberger udf_vptofh (struct vnode *vp, struct fid *fhp) 602*03998195SJoerg Sonnenberger { 603*03998195SJoerg Sonnenberger struct udf_node *node; 604*03998195SJoerg Sonnenberger struct ifid *ifhp; 605*03998195SJoerg Sonnenberger 606*03998195SJoerg Sonnenberger node = VTON(vp); 607*03998195SJoerg Sonnenberger ifhp = (struct ifid *)fhp; 608*03998195SJoerg Sonnenberger ifhp->ifid_len = sizeof(struct ifid); 609*03998195SJoerg Sonnenberger ifhp->ifid_ino = node->hash_id; 610*03998195SJoerg Sonnenberger 611*03998195SJoerg Sonnenberger return(0); 612*03998195SJoerg Sonnenberger } 613*03998195SJoerg Sonnenberger 614*03998195SJoerg Sonnenberger static int 615*03998195SJoerg Sonnenberger udf_find_partmaps(struct udf_mnt *udfmp, struct logvol_desc *lvd) 616*03998195SJoerg Sonnenberger { 617*03998195SJoerg Sonnenberger union udf_pmap *pmap; 618*03998195SJoerg Sonnenberger struct part_map_spare *pms; 619*03998195SJoerg Sonnenberger struct regid *pmap_id; 620*03998195SJoerg Sonnenberger struct buf *bp; 621*03998195SJoerg Sonnenberger unsigned char regid_id[UDF_REGID_ID_SIZE + 1]; 622*03998195SJoerg Sonnenberger int ptype, psize, error; 623*03998195SJoerg Sonnenberger unsigned int i; 624*03998195SJoerg Sonnenberger 625*03998195SJoerg Sonnenberger for (i = 0; i < lvd->n_pm; i++) { 626*03998195SJoerg Sonnenberger pmap = (union udf_pmap *)&lvd->maps[i * UDF_PMAP_SIZE]; 627*03998195SJoerg Sonnenberger ptype = pmap->data[0]; 628*03998195SJoerg Sonnenberger psize = pmap->data[1]; 629*03998195SJoerg Sonnenberger if (((ptype != 1) && (ptype != 2)) || 630*03998195SJoerg Sonnenberger ((psize != UDF_PMAP_SIZE) && (psize != 6))) { 631*03998195SJoerg Sonnenberger printf("Invalid partition map found\n"); 632*03998195SJoerg Sonnenberger return(1); 633*03998195SJoerg Sonnenberger } 634*03998195SJoerg Sonnenberger 635*03998195SJoerg Sonnenberger if (ptype == 1) { 636*03998195SJoerg Sonnenberger /* Type 1 map. We don't care */ 637*03998195SJoerg Sonnenberger continue; 638*03998195SJoerg Sonnenberger } 639*03998195SJoerg Sonnenberger 640*03998195SJoerg Sonnenberger /* Type 2 map. Gotta find out the details */ 641*03998195SJoerg Sonnenberger pmap_id = (struct regid *)&pmap->data[4]; 642*03998195SJoerg Sonnenberger bzero(®id_id[0], UDF_REGID_ID_SIZE); 643*03998195SJoerg Sonnenberger bcopy(&pmap_id->id[0], ®id_id[0], UDF_REGID_ID_SIZE); 644*03998195SJoerg Sonnenberger 645*03998195SJoerg Sonnenberger if (bcmp(®id_id[0], "*UDF Sparable Partition", 646*03998195SJoerg Sonnenberger UDF_REGID_ID_SIZE)) { 647*03998195SJoerg Sonnenberger printf("Unsupported partition map: %s\n", ®id_id[0]); 648*03998195SJoerg Sonnenberger return(1); 649*03998195SJoerg Sonnenberger } 650*03998195SJoerg Sonnenberger 651*03998195SJoerg Sonnenberger pms = &pmap->pms; 652*03998195SJoerg Sonnenberger udfmp->s_table = malloc(pms->st_size, M_UDFMOUNT, 653*03998195SJoerg Sonnenberger M_WAITOK | M_ZERO); 654*03998195SJoerg Sonnenberger if (udfmp->s_table == NULL) 655*03998195SJoerg Sonnenberger return(ENOMEM); 656*03998195SJoerg Sonnenberger 657*03998195SJoerg Sonnenberger /* Calculate the number of sectors per packet. */ 658*03998195SJoerg Sonnenberger /* XXX Logical or physical? */ 659*03998195SJoerg Sonnenberger udfmp->p_sectors = pms->packet_len / udfmp->bsize; 660*03998195SJoerg Sonnenberger 661*03998195SJoerg Sonnenberger /* 662*03998195SJoerg Sonnenberger * XXX If reading the first Sparing Table fails, should look 663*03998195SJoerg Sonnenberger * for another table. 664*03998195SJoerg Sonnenberger */ 665*03998195SJoerg Sonnenberger if ((error = udf_readlblks(udfmp, pms->st_loc[0], pms->st_size, 666*03998195SJoerg Sonnenberger &bp)) != 0) { 667*03998195SJoerg Sonnenberger printf("Failed to read Sparing Table at sector %d\n", 668*03998195SJoerg Sonnenberger pms->st_loc[0]); 669*03998195SJoerg Sonnenberger return(error); 670*03998195SJoerg Sonnenberger } 671*03998195SJoerg Sonnenberger bcopy(bp->b_data, udfmp->s_table, pms->st_size); 672*03998195SJoerg Sonnenberger brelse(bp); 673*03998195SJoerg Sonnenberger 674*03998195SJoerg Sonnenberger if (udf_checktag(&udfmp->s_table->tag, 0)) { 675*03998195SJoerg Sonnenberger printf("Invalid sparing table found\n"); 676*03998195SJoerg Sonnenberger return(EINVAL); 677*03998195SJoerg Sonnenberger } 678*03998195SJoerg Sonnenberger 679*03998195SJoerg Sonnenberger /* See how many valid entries there are here. The list is 680*03998195SJoerg Sonnenberger * supposed to be sorted. 0xfffffff0 and higher are not valid 681*03998195SJoerg Sonnenberger */ 682*03998195SJoerg Sonnenberger for (i = 0; i < udfmp->s_table->rt_l; i++) { 683*03998195SJoerg Sonnenberger udfmp->s_table_entries = i; 684*03998195SJoerg Sonnenberger if (udfmp->s_table->entries[i].org >= 0xfffffff0) 685*03998195SJoerg Sonnenberger break; 686*03998195SJoerg Sonnenberger } 687*03998195SJoerg Sonnenberger } 688*03998195SJoerg Sonnenberger 689*03998195SJoerg Sonnenberger return(0); 690*03998195SJoerg Sonnenberger } 691