103998195SJoerg Sonnenberger /*- 203998195SJoerg Sonnenberger * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org> 303998195SJoerg Sonnenberger * All rights reserved. 403998195SJoerg Sonnenberger * 503998195SJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without 603998195SJoerg Sonnenberger * modification, are permitted provided that the following conditions 703998195SJoerg Sonnenberger * are met: 803998195SJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright 903998195SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer. 1003998195SJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright 1103998195SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the 1203998195SJoerg Sonnenberger * documentation and/or other materials provided with the distribution. 1303998195SJoerg Sonnenberger * 1403998195SJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1503998195SJoerg Sonnenberger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1603998195SJoerg Sonnenberger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1703998195SJoerg Sonnenberger * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1803998195SJoerg Sonnenberger * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1903998195SJoerg Sonnenberger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2003998195SJoerg Sonnenberger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2103998195SJoerg Sonnenberger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2203998195SJoerg Sonnenberger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2303998195SJoerg Sonnenberger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2403998195SJoerg Sonnenberger * SUCH DAMAGE. 2503998195SJoerg Sonnenberger * 2603998195SJoerg Sonnenberger * $FreeBSD: src/sys/fs/udf/udf_vfsops.c,v 1.16 2003/11/05 06:56:08 scottl Exp $ 2703998195SJoerg Sonnenberger */ 2803998195SJoerg Sonnenberger 2903998195SJoerg Sonnenberger /* udf_vfsops.c */ 3003998195SJoerg Sonnenberger /* Implement the VFS side of things */ 3103998195SJoerg Sonnenberger 3203998195SJoerg Sonnenberger /* 3303998195SJoerg Sonnenberger * Ok, here's how it goes. The UDF specs are pretty clear on how each data 3403998195SJoerg Sonnenberger * structure is made up, but not very clear on how they relate to each other. 3503998195SJoerg Sonnenberger * Here is the skinny... This demostrates a filesystem with one file in the 3603998195SJoerg Sonnenberger * root directory. Subdirectories are treated just as normal files, but they 3703998195SJoerg Sonnenberger * have File Id Descriptors of their children as their file data. As for the 3803998195SJoerg Sonnenberger * Anchor Volume Descriptor Pointer, it can exist in two of the following three 3903998195SJoerg Sonnenberger * places: sector 256, sector n (the max sector of the disk), or sector 4003998195SJoerg Sonnenberger * n - 256. It's a pretty good bet that one will exist at sector 256 though. 4103998195SJoerg Sonnenberger * One caveat is unclosed CD media. For that, sector 256 cannot be written, 4203998195SJoerg Sonnenberger * so the Anchor Volume Descriptor Pointer can exist at sector 512 until the 4303998195SJoerg Sonnenberger * media is closed. 4403998195SJoerg Sonnenberger * 4503998195SJoerg Sonnenberger * Sector: 4603998195SJoerg Sonnenberger * 256: 4703998195SJoerg Sonnenberger * n: Anchor Volume Descriptor Pointer 4803998195SJoerg Sonnenberger * n - 256: | 4903998195SJoerg Sonnenberger * | 5003998195SJoerg Sonnenberger * |-->Main Volume Descriptor Sequence 5103998195SJoerg Sonnenberger * | | 5203998195SJoerg Sonnenberger * | | 5303998195SJoerg Sonnenberger * | |-->Logical Volume Descriptor 5403998195SJoerg Sonnenberger * | | 5503998195SJoerg Sonnenberger * |-->Partition Descriptor | 5603998195SJoerg Sonnenberger * | | 5703998195SJoerg Sonnenberger * | | 5803998195SJoerg Sonnenberger * |-->Fileset Descriptor 5903998195SJoerg Sonnenberger * | 6003998195SJoerg Sonnenberger * | 6103998195SJoerg Sonnenberger * |-->Root Dir File Entry 6203998195SJoerg Sonnenberger * | 6303998195SJoerg Sonnenberger * | 6403998195SJoerg Sonnenberger * |-->File data: 6503998195SJoerg Sonnenberger * File Id Descriptor 6603998195SJoerg Sonnenberger * | 6703998195SJoerg Sonnenberger * | 6803998195SJoerg Sonnenberger * |-->File Entry 6903998195SJoerg Sonnenberger * | 7003998195SJoerg Sonnenberger * | 7103998195SJoerg Sonnenberger * |-->File data 7203998195SJoerg Sonnenberger */ 7303998195SJoerg Sonnenberger 7403998195SJoerg Sonnenberger #include <sys/types.h> 7503998195SJoerg Sonnenberger #include <sys/param.h> 7603998195SJoerg Sonnenberger #include <sys/systm.h> 7703998195SJoerg Sonnenberger #include <sys/uio.h> 7803998195SJoerg Sonnenberger #include <sys/buf.h> 7903998195SJoerg Sonnenberger #include <sys/conf.h> 8003998195SJoerg Sonnenberger #include <sys/fcntl.h> 8103998195SJoerg Sonnenberger #include <sys/module.h> 8203998195SJoerg Sonnenberger #include <sys/kernel.h> 8303998195SJoerg Sonnenberger #include <sys/malloc.h> 8403998195SJoerg Sonnenberger #include <sys/mount.h> 85fad57d0eSMatthew Dillon #include <sys/nlookup.h> 8603998195SJoerg Sonnenberger #include <sys/proc.h> 87895c1f85SMichael Neumann #include <sys/priv.h> 8803998195SJoerg Sonnenberger #include <sys/queue.h> 8903998195SJoerg Sonnenberger #include <sys/vnode.h> 9003998195SJoerg Sonnenberger 9154341a3bSMatthew Dillon #include <sys/buf2.h> 9254341a3bSMatthew Dillon 9303998195SJoerg Sonnenberger #include <vfs/udf/ecma167-udf.h> 9403998195SJoerg Sonnenberger #include <vfs/udf/osta.h> 9503998195SJoerg Sonnenberger #include <vfs/udf/udf.h> 9603998195SJoerg Sonnenberger #include <vfs/udf/udf_mount.h> 9703998195SJoerg Sonnenberger 9866a1ddf5SMatthew Dillon extern struct vop_ops udf_vnode_vops; 990961aa92SMatthew Dillon 10003998195SJoerg Sonnenberger MALLOC_DEFINE(M_UDFNODE, "UDF node", "UDF node structure"); 10103998195SJoerg Sonnenberger MALLOC_DEFINE(M_UDFMOUNT, "UDF mount", "UDF mount structure"); 10203998195SJoerg Sonnenberger MALLOC_DEFINE(M_UDFFENTRY, "UDF fentry", "UDF file entry structure"); 10303998195SJoerg Sonnenberger 104acde96dbSMatthew Dillon static int udf_mount(struct mount *, char *, caddr_t, struct ucred *); 105acde96dbSMatthew Dillon static int udf_unmount(struct mount *, int); 10603998195SJoerg Sonnenberger static int udf_root(struct mount *, struct vnode **); 107acde96dbSMatthew Dillon static int udf_statfs(struct mount *, struct statfs *, struct ucred *); 10867863d04SMatthew Dillon static int udf_fhtovp(struct mount *, struct vnode *, 10967863d04SMatthew Dillon struct fid *, struct vnode **); 11003998195SJoerg Sonnenberger static int udf_vptofh(struct vnode *, struct fid *); 11103998195SJoerg Sonnenberger 11203998195SJoerg Sonnenberger static int udf_find_partmaps(struct udf_mnt *, struct logvol_desc *); 11303998195SJoerg Sonnenberger 11403998195SJoerg Sonnenberger static struct vfsops udf_vfsops = { 11543c45e8fSHiten Pandya .vfs_mount = udf_mount, 11643c45e8fSHiten Pandya .vfs_unmount = udf_unmount, 11743c45e8fSHiten Pandya .vfs_root = udf_root, 11843c45e8fSHiten Pandya .vfs_statfs = udf_statfs, 11943c45e8fSHiten Pandya .vfs_sync = vfs_stdsync, 12043c45e8fSHiten Pandya .vfs_vget = udf_vget, 12143c45e8fSHiten Pandya .vfs_fhtovp = udf_fhtovp, 12243c45e8fSHiten Pandya .vfs_vptofh = udf_vptofh 12303998195SJoerg Sonnenberger }; 12403998195SJoerg Sonnenberger VFS_SET(udf_vfsops, udf, VFCF_READONLY); 12503998195SJoerg Sonnenberger 12603998195SJoerg Sonnenberger MODULE_VERSION(udf, 1); 12703998195SJoerg Sonnenberger 128acde96dbSMatthew Dillon static int udf_mountfs(struct vnode *, struct mount *); 12903998195SJoerg Sonnenberger 13003998195SJoerg Sonnenberger static int 131acde96dbSMatthew Dillon udf_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) 13203998195SJoerg Sonnenberger { 13303998195SJoerg Sonnenberger struct vnode *devvp; /* vnode of the mount device */ 13403998195SJoerg Sonnenberger struct udf_args args; 1354090d6ffSSascha Wildner struct udf_mnt *imp = NULL; 13603998195SJoerg Sonnenberger size_t size; 13703998195SJoerg Sonnenberger int error; 138fad57d0eSMatthew Dillon struct nlookupdata nd; 13903998195SJoerg Sonnenberger 14003998195SJoerg Sonnenberger if ((mp->mnt_flag & MNT_RDONLY) == 0) 14103998195SJoerg Sonnenberger return (EROFS); 14203998195SJoerg Sonnenberger 14303998195SJoerg Sonnenberger /* 14403998195SJoerg Sonnenberger * No root filesystem support. Probably not a big deal, since the 14503998195SJoerg Sonnenberger * bootloader doesn't understand UDF. 14603998195SJoerg Sonnenberger */ 14703998195SJoerg Sonnenberger if (mp->mnt_flag & MNT_ROOTFS) 14803998195SJoerg Sonnenberger return (ENOTSUP); 14903998195SJoerg Sonnenberger 15003998195SJoerg Sonnenberger if ((error = copyin(data, (caddr_t)&args, sizeof(struct udf_args)))) 15103998195SJoerg Sonnenberger return(error); 15203998195SJoerg Sonnenberger 15303998195SJoerg Sonnenberger if (mp->mnt_flag & MNT_UPDATE) { 15403998195SJoerg Sonnenberger imp = VFSTOUDFFS(mp); 15503998195SJoerg Sonnenberger if (args.fspec == NULL) 15603998195SJoerg Sonnenberger return(vfs_export(mp, &imp->im_export, &args.export)); 15703998195SJoerg Sonnenberger } 15803998195SJoerg Sonnenberger 15903998195SJoerg Sonnenberger /* Check that the mount device exists */ 160fad57d0eSMatthew Dillon devvp = NULL; 161fad57d0eSMatthew Dillon error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); 162fad57d0eSMatthew Dillon if (error == 0) 163fad57d0eSMatthew Dillon error = nlookup(&nd); 164fad57d0eSMatthew Dillon if (error == 0) 16528623bf9SMatthew Dillon error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp); 166fad57d0eSMatthew Dillon nlookup_done(&nd); 167fad57d0eSMatthew Dillon if (error) 16803998195SJoerg Sonnenberger return (error); 16903998195SJoerg Sonnenberger 17003998195SJoerg Sonnenberger if (vn_isdisk(devvp, &error) == 0) { 17103998195SJoerg Sonnenberger vrele(devvp); 17203998195SJoerg Sonnenberger return(error); 17303998195SJoerg Sonnenberger } 17403998195SJoerg Sonnenberger 17503998195SJoerg Sonnenberger /* Check the access rights on the mount device */ 176ca466baeSMatthew Dillon vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 177cb66845aSMatthew Dillon error = VOP_EACCESS(devvp, VREAD, cred); 17803998195SJoerg Sonnenberger if (error) 179895c1f85SMichael Neumann error = priv_check_cred(cred, PRIV_ROOT, 0); 18003998195SJoerg Sonnenberger if (error) { 18103998195SJoerg Sonnenberger vput(devvp); 18203998195SJoerg Sonnenberger return(error); 18303998195SJoerg Sonnenberger } 184a11aaa81SMatthew Dillon vn_unlock(devvp); 18503998195SJoerg Sonnenberger 186acde96dbSMatthew Dillon if ((error = udf_mountfs(devvp, mp))) { 18703998195SJoerg Sonnenberger vrele(devvp); 18803998195SJoerg Sonnenberger return(error); 18903998195SJoerg Sonnenberger } 19003998195SJoerg Sonnenberger 19103998195SJoerg Sonnenberger imp = VFSTOUDFFS(mp); 19203998195SJoerg Sonnenberger 19303998195SJoerg Sonnenberger imp->im_flags = args.flags; 19403998195SJoerg Sonnenberger 19503998195SJoerg Sonnenberger copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 19603998195SJoerg Sonnenberger bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 197acde96dbSMatthew Dillon udf_statfs(mp, &mp->mnt_stat, cred); 19803998195SJoerg Sonnenberger return(0); 1994a77c3abSDavid Rhodus } 20003998195SJoerg Sonnenberger 20103998195SJoerg Sonnenberger /* 20203998195SJoerg Sonnenberger * Check the descriptor tag for both the correct id and correct checksum. 20303998195SJoerg Sonnenberger * Return zero if all is good, EINVAL if not. 20403998195SJoerg Sonnenberger */ 20503998195SJoerg Sonnenberger int 20603998195SJoerg Sonnenberger udf_checktag(struct desc_tag *tag, uint16_t id) 20703998195SJoerg Sonnenberger { 20803998195SJoerg Sonnenberger uint8_t *itag; 20903998195SJoerg Sonnenberger uint8_t i, cksum = 0; 21003998195SJoerg Sonnenberger 21103998195SJoerg Sonnenberger itag = (uint8_t *)tag; 21203998195SJoerg Sonnenberger 21303998195SJoerg Sonnenberger if (tag->id != id) 21403998195SJoerg Sonnenberger return(EINVAL); 21503998195SJoerg Sonnenberger 21603998195SJoerg Sonnenberger for (i = 0; i < 15; i++) 21703998195SJoerg Sonnenberger cksum = cksum + itag[i]; 21803998195SJoerg Sonnenberger cksum = cksum - itag[4]; 21903998195SJoerg Sonnenberger 22003998195SJoerg Sonnenberger if (cksum == tag->cksum) 22103998195SJoerg Sonnenberger return(0); 22203998195SJoerg Sonnenberger 22303998195SJoerg Sonnenberger return(EINVAL); 22403998195SJoerg Sonnenberger } 22503998195SJoerg Sonnenberger 22603998195SJoerg Sonnenberger static int 227acde96dbSMatthew Dillon udf_mountfs(struct vnode *devvp, struct mount *mp) 228e4c9c0c8SMatthew Dillon { 22903998195SJoerg Sonnenberger struct buf *bp = NULL; 23003998195SJoerg Sonnenberger struct anchor_vdp avdp; 23103998195SJoerg Sonnenberger struct udf_mnt *udfmp = NULL; 23203998195SJoerg Sonnenberger struct part_desc *pd; 23303998195SJoerg Sonnenberger struct logvol_desc *lvd; 23403998195SJoerg Sonnenberger struct fileset_desc *fsd; 23503998195SJoerg Sonnenberger struct file_entry *root_fentry; 236b13267a5SMatthew Dillon cdev_t dev; 23703998195SJoerg Sonnenberger uint32_t sector, size, mvds_start, mvds_end; 23803998195SJoerg Sonnenberger uint32_t fsd_offset = 0; 23903998195SJoerg Sonnenberger uint16_t part_num = 0, fsd_part = 0; 24003998195SJoerg Sonnenberger int error = EINVAL, needclose = 0; 24103998195SJoerg Sonnenberger int logvol_found = 0, part_found = 0, fsd_found = 0; 24203998195SJoerg Sonnenberger int bsize; 24303998195SJoerg Sonnenberger 24403998195SJoerg Sonnenberger /* 24503998195SJoerg Sonnenberger * Disallow multiple mounts of the same device. Flush the buffer 24603998195SJoerg Sonnenberger * cache for the device. 24703998195SJoerg Sonnenberger */ 24803998195SJoerg Sonnenberger if ((error = vfs_mountedon(devvp))) 24903998195SJoerg Sonnenberger return(error); 2508be7edadSMatthew Dillon if (vcount(devvp) > 0) 25103998195SJoerg Sonnenberger return(EBUSY); 25287de5057SMatthew Dillon if ((error = vinvalbuf(devvp, V_SAVE, 0, 0))) 25303998195SJoerg Sonnenberger return(error); 25403998195SJoerg Sonnenberger 255ca466baeSMatthew Dillon vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 25687de5057SMatthew Dillon error = VOP_OPEN(devvp, FREAD, FSCRED, NULL); 257a11aaa81SMatthew Dillon vn_unlock(devvp); 25803998195SJoerg Sonnenberger if (error) 25903998195SJoerg Sonnenberger return(error); 26003998195SJoerg Sonnenberger needclose = 1; 261e4c9c0c8SMatthew Dillon dev = devvp->v_rdev; 26203998195SJoerg Sonnenberger 263efda3bd0SMatthew Dillon udfmp = kmalloc(sizeof(*udfmp), M_UDFMOUNT, M_WAITOK | M_ZERO); 26403998195SJoerg Sonnenberger 26503998195SJoerg Sonnenberger mp->mnt_data = (qaddr_t)udfmp; 266e4c9c0c8SMatthew Dillon mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 26703998195SJoerg Sonnenberger mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 26803998195SJoerg Sonnenberger mp->mnt_maxsymlinklen = 0; 26903998195SJoerg Sonnenberger mp->mnt_flag |= MNT_LOCAL; 27003998195SJoerg Sonnenberger udfmp->im_mountp = mp; 271e4c9c0c8SMatthew Dillon udfmp->im_dev = dev; 27203998195SJoerg Sonnenberger udfmp->im_devvp = devvp; 27303998195SJoerg Sonnenberger 27403998195SJoerg Sonnenberger bsize = 2048; /* XXX Should probe the media for it's size */ 27503998195SJoerg Sonnenberger 27603998195SJoerg Sonnenberger /* 27703998195SJoerg Sonnenberger * Get the Anchor Volume Descriptor Pointer from sector 256. 27803998195SJoerg Sonnenberger * XXX Should also check sector n - 256, n, and 512. 27903998195SJoerg Sonnenberger */ 28003998195SJoerg Sonnenberger sector = 256; 28154078292SMatthew Dillon if ((error = bread(devvp, (off_t)sector * bsize, bsize, &bp)) != 0) 28203998195SJoerg Sonnenberger goto bail; 28303998195SJoerg Sonnenberger if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR))) 28403998195SJoerg Sonnenberger goto bail; 28503998195SJoerg Sonnenberger 28603998195SJoerg Sonnenberger bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp)); 28703998195SJoerg Sonnenberger brelse(bp); 28803998195SJoerg Sonnenberger bp = NULL; 28903998195SJoerg Sonnenberger 29003998195SJoerg Sonnenberger /* 29103998195SJoerg Sonnenberger * Extract the Partition Descriptor and Logical Volume Descriptor 29203998195SJoerg Sonnenberger * from the Volume Descriptor Sequence. 29303998195SJoerg Sonnenberger * XXX Should we care about the partition type right now? 29403998195SJoerg Sonnenberger * XXX What about multiple partitions? 29503998195SJoerg Sonnenberger */ 29603998195SJoerg Sonnenberger mvds_start = avdp.main_vds_ex.loc; 29703998195SJoerg Sonnenberger mvds_end = mvds_start + (avdp.main_vds_ex.len - 1) / bsize; 29803998195SJoerg Sonnenberger for (sector = mvds_start; sector < mvds_end; sector++) { 29954078292SMatthew Dillon if ((error = bread(devvp, (off_t)sector * bsize, bsize, 30003998195SJoerg Sonnenberger &bp)) != 0) { 301086c1d7eSSascha Wildner kprintf("Can't read sector %d of VDS\n", sector); 30203998195SJoerg Sonnenberger goto bail; 30303998195SJoerg Sonnenberger } 30403998195SJoerg Sonnenberger lvd = (struct logvol_desc *)bp->b_data; 30503998195SJoerg Sonnenberger if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) { 30603998195SJoerg Sonnenberger udfmp->bsize = lvd->lb_size; 30703998195SJoerg Sonnenberger udfmp->bmask = udfmp->bsize - 1; 30803998195SJoerg Sonnenberger udfmp->bshift = ffs(udfmp->bsize) - 1; 30903998195SJoerg Sonnenberger fsd_part = lvd->_lvd_use.fsd_loc.loc.part_num; 31003998195SJoerg Sonnenberger fsd_offset = lvd->_lvd_use.fsd_loc.loc.lb_num; 31103998195SJoerg Sonnenberger if (udf_find_partmaps(udfmp, lvd)) 31203998195SJoerg Sonnenberger break; 31303998195SJoerg Sonnenberger logvol_found = 1; 31403998195SJoerg Sonnenberger } 31503998195SJoerg Sonnenberger pd = (struct part_desc *)bp->b_data; 31603998195SJoerg Sonnenberger if (!udf_checktag(&pd->tag, TAGID_PARTITION)) { 31703998195SJoerg Sonnenberger part_found = 1; 31803998195SJoerg Sonnenberger part_num = pd->part_num; 31903998195SJoerg Sonnenberger udfmp->part_len = pd->part_len; 32003998195SJoerg Sonnenberger udfmp->part_start = pd->start_loc; 32103998195SJoerg Sonnenberger } 32203998195SJoerg Sonnenberger 32303998195SJoerg Sonnenberger brelse(bp); 32403998195SJoerg Sonnenberger bp = NULL; 32503998195SJoerg Sonnenberger if ((part_found) && (logvol_found)) 32603998195SJoerg Sonnenberger break; 32703998195SJoerg Sonnenberger } 32803998195SJoerg Sonnenberger 32903998195SJoerg Sonnenberger if (!part_found || !logvol_found) { 33003998195SJoerg Sonnenberger error = EINVAL; 33103998195SJoerg Sonnenberger goto bail; 33203998195SJoerg Sonnenberger } 33303998195SJoerg Sonnenberger 33403998195SJoerg Sonnenberger if (fsd_part != part_num) { 335086c1d7eSSascha Wildner kprintf("FSD does not lie within the partition!\n"); 33603998195SJoerg Sonnenberger error = EINVAL; 33703998195SJoerg Sonnenberger goto bail; 33803998195SJoerg Sonnenberger } 33903998195SJoerg Sonnenberger 34003998195SJoerg Sonnenberger 34103998195SJoerg Sonnenberger /* 34203998195SJoerg Sonnenberger * Grab the Fileset Descriptor 34303998195SJoerg Sonnenberger * Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing 34403998195SJoerg Sonnenberger * me in the right direction here. 34503998195SJoerg Sonnenberger */ 34603998195SJoerg Sonnenberger sector = udfmp->part_start + fsd_offset; 34703998195SJoerg Sonnenberger if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) { 348086c1d7eSSascha Wildner kprintf("Cannot read sector %d of FSD\n", sector); 34903998195SJoerg Sonnenberger goto bail; 35003998195SJoerg Sonnenberger } 35103998195SJoerg Sonnenberger fsd = (struct fileset_desc *)bp->b_data; 35203998195SJoerg Sonnenberger if (!udf_checktag(&fsd->tag, TAGID_FSD)) { 35303998195SJoerg Sonnenberger fsd_found = 1; 35403998195SJoerg Sonnenberger bcopy(&fsd->rootdir_icb, &udfmp->root_icb, 35503998195SJoerg Sonnenberger sizeof(struct long_ad)); 35603998195SJoerg Sonnenberger } 35703998195SJoerg Sonnenberger 35803998195SJoerg Sonnenberger brelse(bp); 35903998195SJoerg Sonnenberger bp = NULL; 36003998195SJoerg Sonnenberger 36103998195SJoerg Sonnenberger if (!fsd_found) { 362086c1d7eSSascha Wildner kprintf("Couldn't find the fsd\n"); 36303998195SJoerg Sonnenberger error = EINVAL; 36403998195SJoerg Sonnenberger goto bail; 36503998195SJoerg Sonnenberger } 36603998195SJoerg Sonnenberger 36766a1ddf5SMatthew Dillon vfs_add_vnodeops(mp, &udf_vnode_vops, &mp->mnt_vn_norm_ops); 3680961aa92SMatthew Dillon 36903998195SJoerg Sonnenberger /* 37003998195SJoerg Sonnenberger * Find the file entry for the root directory. 37103998195SJoerg Sonnenberger */ 37203998195SJoerg Sonnenberger sector = udfmp->root_icb.loc.lb_num + udfmp->part_start; 37303998195SJoerg Sonnenberger size = udfmp->root_icb.len; 37403998195SJoerg Sonnenberger if ((error = udf_readlblks(udfmp, sector, size, &bp)) != 0) { 375086c1d7eSSascha Wildner kprintf("Cannot read sector %d\n", sector); 37603998195SJoerg Sonnenberger goto bail; 37703998195SJoerg Sonnenberger } 37803998195SJoerg Sonnenberger 37903998195SJoerg Sonnenberger root_fentry = (struct file_entry *)bp->b_data; 38003998195SJoerg Sonnenberger if ((error = udf_checktag(&root_fentry->tag, TAGID_FENTRY))) { 381086c1d7eSSascha Wildner kprintf("Invalid root file entry!\n"); 38203998195SJoerg Sonnenberger goto bail; 38303998195SJoerg Sonnenberger } 38403998195SJoerg Sonnenberger 38503998195SJoerg Sonnenberger brelse(bp); 38603998195SJoerg Sonnenberger bp = NULL; 38703998195SJoerg Sonnenberger 388a3c18566SMatthew Dillon lwkt_token_init(&udfmp->hash_token, "udfihash"); 38903998195SJoerg Sonnenberger udfmp->hashtbl = phashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, &udfmp->hashsz); 39003998195SJoerg Sonnenberger 39103998195SJoerg Sonnenberger return(0); 39203998195SJoerg Sonnenberger 39303998195SJoerg Sonnenberger bail: 39403998195SJoerg Sonnenberger if (udfmp != NULL) 395efda3bd0SMatthew Dillon kfree(udfmp, M_UDFMOUNT); 39603998195SJoerg Sonnenberger if (bp != NULL) 39703998195SJoerg Sonnenberger brelse(bp); 398*12cdc371SMatthew Dillon if (needclose) { 399*12cdc371SMatthew Dillon vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 40087de5057SMatthew Dillon VOP_CLOSE(devvp, FREAD); 401*12cdc371SMatthew Dillon vn_unlock(devvp); 402*12cdc371SMatthew Dillon } 40303998195SJoerg Sonnenberger return(error); 4044a77c3abSDavid Rhodus } 40503998195SJoerg Sonnenberger 40603998195SJoerg Sonnenberger static int 407acde96dbSMatthew Dillon udf_unmount(struct mount *mp, int mntflags) 40803998195SJoerg Sonnenberger { 40903998195SJoerg Sonnenberger struct udf_mnt *udfmp; 41003998195SJoerg Sonnenberger int error, flags = 0; 41103998195SJoerg Sonnenberger 41203998195SJoerg Sonnenberger udfmp = VFSTOUDFFS(mp); 41303998195SJoerg Sonnenberger 41403998195SJoerg Sonnenberger if (mntflags & MNT_FORCE) 41503998195SJoerg Sonnenberger flags |= FORCECLOSE; 41603998195SJoerg Sonnenberger 41703998195SJoerg Sonnenberger if ((error = vflush(mp, 0, flags))) 41803998195SJoerg Sonnenberger return (error); 41903998195SJoerg Sonnenberger 420e4c9c0c8SMatthew Dillon udfmp->im_devvp->v_rdev->si_mountpoint = NULL; 421*12cdc371SMatthew Dillon vn_lock(udfmp->im_devvp, LK_EXCLUSIVE | LK_RETRY); 42287de5057SMatthew Dillon error = VOP_CLOSE(udfmp->im_devvp, FREAD); 423*12cdc371SMatthew Dillon vn_unlock(udfmp->im_devvp); 42403998195SJoerg Sonnenberger vrele(udfmp->im_devvp); 42503998195SJoerg Sonnenberger 42603998195SJoerg Sonnenberger if (udfmp->s_table) 427efda3bd0SMatthew Dillon kfree(udfmp->s_table, M_UDFMOUNT); 42803998195SJoerg Sonnenberger if (udfmp->hashtbl) 429efda3bd0SMatthew Dillon kfree(udfmp->hashtbl, M_UDFMOUNT); 430efda3bd0SMatthew Dillon kfree(udfmp, M_UDFMOUNT); 43103998195SJoerg Sonnenberger 43203998195SJoerg Sonnenberger mp->mnt_data = (qaddr_t)0; 43303998195SJoerg Sonnenberger mp->mnt_flag &= ~MNT_LOCAL; 43403998195SJoerg Sonnenberger 43503998195SJoerg Sonnenberger return (error); 43603998195SJoerg Sonnenberger } 43703998195SJoerg Sonnenberger 43803998195SJoerg Sonnenberger static int 43903998195SJoerg Sonnenberger udf_root(struct mount *mp, struct vnode **vpp) 44003998195SJoerg Sonnenberger { 44103998195SJoerg Sonnenberger struct udf_mnt *udfmp; 44203998195SJoerg Sonnenberger struct vnode *vp; 44303998195SJoerg Sonnenberger ino_t id; 44403998195SJoerg Sonnenberger int error; 44503998195SJoerg Sonnenberger 44603998195SJoerg Sonnenberger udfmp = VFSTOUDFFS(mp); 44703998195SJoerg Sonnenberger 44803998195SJoerg Sonnenberger id = udf_getid(&udfmp->root_icb); 44903998195SJoerg Sonnenberger 450b9b0a6d0SMatthew Dillon error = udf_vget(mp, NULL, id, vpp); 45103998195SJoerg Sonnenberger if (error) 45203998195SJoerg Sonnenberger return(error); 45303998195SJoerg Sonnenberger 45403998195SJoerg Sonnenberger vp = *vpp; 4552247fe02SMatthew Dillon vsetflags(vp, VROOT); 45603998195SJoerg Sonnenberger udfmp->root_vp = vp; 45703998195SJoerg Sonnenberger 45803998195SJoerg Sonnenberger return(0); 45903998195SJoerg Sonnenberger } 46003998195SJoerg Sonnenberger 46103998195SJoerg Sonnenberger static int 462acde96dbSMatthew Dillon udf_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 46303998195SJoerg Sonnenberger { 46403998195SJoerg Sonnenberger struct udf_mnt *udfmp; 46503998195SJoerg Sonnenberger 46603998195SJoerg Sonnenberger udfmp = VFSTOUDFFS(mp); 46703998195SJoerg Sonnenberger 46803998195SJoerg Sonnenberger sbp->f_bsize = udfmp->bsize; 46903998195SJoerg Sonnenberger sbp->f_iosize = udfmp->bsize; 47003998195SJoerg Sonnenberger sbp->f_blocks = udfmp->part_len; 47103998195SJoerg Sonnenberger sbp->f_bfree = 0; 47203998195SJoerg Sonnenberger sbp->f_bavail = 0; 47303998195SJoerg Sonnenberger sbp->f_files = 0; 47403998195SJoerg Sonnenberger sbp->f_ffree = 0; 47503998195SJoerg Sonnenberger if (sbp != &mp->mnt_stat) { 47603998195SJoerg Sonnenberger sbp->f_type = mp->mnt_vfc->vfc_typenum; 47703998195SJoerg Sonnenberger bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 47803998195SJoerg Sonnenberger } 47903998195SJoerg Sonnenberger 48003998195SJoerg Sonnenberger return(0); 48103998195SJoerg Sonnenberger } 48203998195SJoerg Sonnenberger 48303998195SJoerg Sonnenberger int 484b9b0a6d0SMatthew Dillon udf_vget(struct mount *mp, struct vnode *dvp, ino_t ino, struct vnode **vpp) 48503998195SJoerg Sonnenberger { 48603998195SJoerg Sonnenberger struct buf *bp; 48703998195SJoerg Sonnenberger struct vnode *devvp; 48803998195SJoerg Sonnenberger struct udf_mnt *udfmp; 48903998195SJoerg Sonnenberger struct vnode *vp; 49003998195SJoerg Sonnenberger struct udf_node *unode; 49103998195SJoerg Sonnenberger struct file_entry *fe; 49203998195SJoerg Sonnenberger int error, sector, size; 49303998195SJoerg Sonnenberger 49403998195SJoerg Sonnenberger udfmp = VFSTOUDFFS(mp); 49503998195SJoerg Sonnenberger 49603998195SJoerg Sonnenberger /* See if we already have this in the cache */ 49703998195SJoerg Sonnenberger if ((error = udf_hashlookup(udfmp, ino, vpp)) != 0) 49803998195SJoerg Sonnenberger return(error); 49903998195SJoerg Sonnenberger if (*vpp != NULL) { 50003998195SJoerg Sonnenberger return(0); 50103998195SJoerg Sonnenberger } 50203998195SJoerg Sonnenberger 50303998195SJoerg Sonnenberger /* 50403998195SJoerg Sonnenberger * Allocate memory and check the tag id's before grabbing a new 50503998195SJoerg Sonnenberger * vnode, since it's hard to roll back if there is a problem. 50603998195SJoerg Sonnenberger */ 507efda3bd0SMatthew Dillon unode = kmalloc(sizeof(*unode), M_UDFNODE, M_WAITOK | M_ZERO); 50803998195SJoerg Sonnenberger 50903998195SJoerg Sonnenberger /* 51003998195SJoerg Sonnenberger * Copy in the file entry. Per the spec, the size can only be 1 block. 51103998195SJoerg Sonnenberger */ 51203998195SJoerg Sonnenberger sector = ino + udfmp->part_start; 51303998195SJoerg Sonnenberger devvp = udfmp->im_devvp; 51403998195SJoerg Sonnenberger if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) { 515086c1d7eSSascha Wildner kprintf("Cannot read sector %d\n", sector); 516efda3bd0SMatthew Dillon kfree(unode, M_UDFNODE); 51703998195SJoerg Sonnenberger return(error); 51803998195SJoerg Sonnenberger } 51903998195SJoerg Sonnenberger 52003998195SJoerg Sonnenberger fe = (struct file_entry *)bp->b_data; 52103998195SJoerg Sonnenberger if (udf_checktag(&fe->tag, TAGID_FENTRY)) { 522086c1d7eSSascha Wildner kprintf("Invalid file entry!\n"); 523efda3bd0SMatthew Dillon kfree(unode, M_UDFNODE); 52403998195SJoerg Sonnenberger brelse(bp); 52503998195SJoerg Sonnenberger return(ENOMEM); 52603998195SJoerg Sonnenberger } 52703998195SJoerg Sonnenberger size = UDF_FENTRY_SIZE + fe->l_ea + fe->l_ad; 528efda3bd0SMatthew Dillon unode->fentry = kmalloc(size, M_UDFFENTRY, M_WAITOK | M_ZERO); 52903998195SJoerg Sonnenberger 53003998195SJoerg Sonnenberger bcopy(bp->b_data, unode->fentry, size); 53103998195SJoerg Sonnenberger 53203998195SJoerg Sonnenberger brelse(bp); 53303998195SJoerg Sonnenberger bp = NULL; 53403998195SJoerg Sonnenberger 53503998195SJoerg Sonnenberger if ((error = udf_allocv(mp, &vp))) { 536086c1d7eSSascha Wildner kprintf("Error from udf_allocv\n"); 537efda3bd0SMatthew Dillon kfree(unode, M_UDFNODE); 53803998195SJoerg Sonnenberger return(error); 53903998195SJoerg Sonnenberger } 54003998195SJoerg Sonnenberger 54103998195SJoerg Sonnenberger unode->i_vnode = vp; 54203998195SJoerg Sonnenberger unode->hash_id = ino; 54303998195SJoerg Sonnenberger unode->i_devvp = udfmp->im_devvp; 54403998195SJoerg Sonnenberger unode->i_dev = udfmp->im_dev; 54503998195SJoerg Sonnenberger unode->udfmp = udfmp; 54603998195SJoerg Sonnenberger vp->v_data = unode; 547597aea93SDavid Rhodus vref(udfmp->im_devvp); 54803998195SJoerg Sonnenberger udf_hashins(unode); 54903998195SJoerg Sonnenberger 55003998195SJoerg Sonnenberger switch (unode->fentry->icbtag.file_type) { 55103998195SJoerg Sonnenberger default: 55203998195SJoerg Sonnenberger vp->v_type = VBAD; 55303998195SJoerg Sonnenberger break; 55403998195SJoerg Sonnenberger case 4: 55503998195SJoerg Sonnenberger vp->v_type = VDIR; 55603998195SJoerg Sonnenberger break; 55703998195SJoerg Sonnenberger case 5: 55803998195SJoerg Sonnenberger vp->v_type = VREG; 55903998195SJoerg Sonnenberger break; 56003998195SJoerg Sonnenberger case 6: 56103998195SJoerg Sonnenberger vp->v_type = VBLK; 56203998195SJoerg Sonnenberger break; 56303998195SJoerg Sonnenberger case 7: 56403998195SJoerg Sonnenberger vp->v_type = VCHR; 56503998195SJoerg Sonnenberger break; 56603998195SJoerg Sonnenberger case 9: 56703998195SJoerg Sonnenberger vp->v_type = VFIFO; 56803998195SJoerg Sonnenberger break; 56903998195SJoerg Sonnenberger case 10: 57003998195SJoerg Sonnenberger vp->v_type = VSOCK; 57103998195SJoerg Sonnenberger break; 57203998195SJoerg Sonnenberger case 12: 57303998195SJoerg Sonnenberger vp->v_type = VLNK; 57403998195SJoerg Sonnenberger break; 57503998195SJoerg Sonnenberger } 5765fd012e0SMatthew Dillon /* 5775fd012e0SMatthew Dillon * Locked and refd vnode returned 5785fd012e0SMatthew Dillon */ 57903998195SJoerg Sonnenberger *vpp = vp; 58003998195SJoerg Sonnenberger 58103998195SJoerg Sonnenberger return(0); 58203998195SJoerg Sonnenberger } 58303998195SJoerg Sonnenberger 58403998195SJoerg Sonnenberger struct ifid { 58503998195SJoerg Sonnenberger u_short ifid_len; 58603998195SJoerg Sonnenberger u_short ifid_pad; 58703998195SJoerg Sonnenberger int ifid_ino; 58803998195SJoerg Sonnenberger long ifid_start; 58903998195SJoerg Sonnenberger }; 59003998195SJoerg Sonnenberger 59103998195SJoerg Sonnenberger static int 59267863d04SMatthew Dillon udf_fhtovp(struct mount *mp, struct vnode *rootvp, 59367863d04SMatthew Dillon struct fid *fhp, struct vnode **vpp) 59403998195SJoerg Sonnenberger { 59503998195SJoerg Sonnenberger struct ifid *ifhp; 59603998195SJoerg Sonnenberger struct vnode *nvp; 59703998195SJoerg Sonnenberger int error; 59803998195SJoerg Sonnenberger 59903998195SJoerg Sonnenberger ifhp = (struct ifid *)fhp; 60003998195SJoerg Sonnenberger 601b9b0a6d0SMatthew Dillon if ((error = VFS_VGET(mp, NULL, ifhp->ifid_ino, &nvp)) != 0) { 60203998195SJoerg Sonnenberger *vpp = NULLVP; 60303998195SJoerg Sonnenberger return(error); 60403998195SJoerg Sonnenberger } 60503998195SJoerg Sonnenberger 60603998195SJoerg Sonnenberger *vpp = nvp; 60703998195SJoerg Sonnenberger return(0); 60803998195SJoerg Sonnenberger } 60903998195SJoerg Sonnenberger 61003998195SJoerg Sonnenberger static int 61103998195SJoerg Sonnenberger udf_vptofh (struct vnode *vp, struct fid *fhp) 61203998195SJoerg Sonnenberger { 61303998195SJoerg Sonnenberger struct udf_node *node; 61403998195SJoerg Sonnenberger struct ifid *ifhp; 61503998195SJoerg Sonnenberger 61603998195SJoerg Sonnenberger node = VTON(vp); 61703998195SJoerg Sonnenberger ifhp = (struct ifid *)fhp; 61803998195SJoerg Sonnenberger ifhp->ifid_len = sizeof(struct ifid); 61903998195SJoerg Sonnenberger ifhp->ifid_ino = node->hash_id; 62003998195SJoerg Sonnenberger 62103998195SJoerg Sonnenberger return(0); 62203998195SJoerg Sonnenberger } 62303998195SJoerg Sonnenberger 62403998195SJoerg Sonnenberger static int 62503998195SJoerg Sonnenberger udf_find_partmaps(struct udf_mnt *udfmp, struct logvol_desc *lvd) 62603998195SJoerg Sonnenberger { 62703998195SJoerg Sonnenberger union udf_pmap *pmap; 62803998195SJoerg Sonnenberger struct part_map_spare *pms; 62903998195SJoerg Sonnenberger struct regid *pmap_id; 63003998195SJoerg Sonnenberger struct buf *bp; 63103998195SJoerg Sonnenberger unsigned char regid_id[UDF_REGID_ID_SIZE + 1]; 63203998195SJoerg Sonnenberger int ptype, psize, error; 63303998195SJoerg Sonnenberger unsigned int i; 63403998195SJoerg Sonnenberger 63503998195SJoerg Sonnenberger for (i = 0; i < lvd->n_pm; i++) { 63603998195SJoerg Sonnenberger pmap = (union udf_pmap *)&lvd->maps[i * UDF_PMAP_SIZE]; 63703998195SJoerg Sonnenberger ptype = pmap->data[0]; 63803998195SJoerg Sonnenberger psize = pmap->data[1]; 63903998195SJoerg Sonnenberger if (((ptype != 1) && (ptype != 2)) || 64003998195SJoerg Sonnenberger ((psize != UDF_PMAP_SIZE) && (psize != 6))) { 641086c1d7eSSascha Wildner kprintf("Invalid partition map found\n"); 64203998195SJoerg Sonnenberger return(1); 64303998195SJoerg Sonnenberger } 64403998195SJoerg Sonnenberger 64503998195SJoerg Sonnenberger if (ptype == 1) { 64603998195SJoerg Sonnenberger /* Type 1 map. We don't care */ 64703998195SJoerg Sonnenberger continue; 64803998195SJoerg Sonnenberger } 64903998195SJoerg Sonnenberger 65003998195SJoerg Sonnenberger /* Type 2 map. Gotta find out the details */ 65103998195SJoerg Sonnenberger pmap_id = (struct regid *)&pmap->data[4]; 65203998195SJoerg Sonnenberger bzero(®id_id[0], UDF_REGID_ID_SIZE); 65303998195SJoerg Sonnenberger bcopy(&pmap_id->id[0], ®id_id[0], UDF_REGID_ID_SIZE); 65403998195SJoerg Sonnenberger 65503998195SJoerg Sonnenberger if (bcmp(®id_id[0], "*UDF Sparable Partition", 65603998195SJoerg Sonnenberger UDF_REGID_ID_SIZE)) { 657086c1d7eSSascha Wildner kprintf("Unsupported partition map: %s\n", ®id_id[0]); 65803998195SJoerg Sonnenberger return(1); 65903998195SJoerg Sonnenberger } 66003998195SJoerg Sonnenberger 66103998195SJoerg Sonnenberger pms = &pmap->pms; 662efda3bd0SMatthew Dillon udfmp->s_table = kmalloc(pms->st_size, M_UDFMOUNT, 66303998195SJoerg Sonnenberger M_WAITOK | M_ZERO); 66403998195SJoerg Sonnenberger 66503998195SJoerg Sonnenberger /* Calculate the number of sectors per packet. */ 66603998195SJoerg Sonnenberger /* XXX Logical or physical? */ 66703998195SJoerg Sonnenberger udfmp->p_sectors = pms->packet_len / udfmp->bsize; 66803998195SJoerg Sonnenberger 66903998195SJoerg Sonnenberger /* 67003998195SJoerg Sonnenberger * XXX If reading the first Sparing Table fails, should look 67103998195SJoerg Sonnenberger * for another table. 67203998195SJoerg Sonnenberger */ 67303998195SJoerg Sonnenberger if ((error = udf_readlblks(udfmp, pms->st_loc[0], pms->st_size, 67403998195SJoerg Sonnenberger &bp)) != 0) { 675ffaa7d78SMatthew Dillon if (bp) 676ffaa7d78SMatthew Dillon brelse(bp); 677086c1d7eSSascha Wildner kprintf("Failed to read Sparing Table at sector %d\n", 67803998195SJoerg Sonnenberger pms->st_loc[0]); 67903998195SJoerg Sonnenberger return(error); 68003998195SJoerg Sonnenberger } 68103998195SJoerg Sonnenberger bcopy(bp->b_data, udfmp->s_table, pms->st_size); 68203998195SJoerg Sonnenberger brelse(bp); 68303998195SJoerg Sonnenberger 68403998195SJoerg Sonnenberger if (udf_checktag(&udfmp->s_table->tag, 0)) { 685086c1d7eSSascha Wildner kprintf("Invalid sparing table found\n"); 68603998195SJoerg Sonnenberger return(EINVAL); 68703998195SJoerg Sonnenberger } 68803998195SJoerg Sonnenberger 68903998195SJoerg Sonnenberger /* See how many valid entries there are here. The list is 69003998195SJoerg Sonnenberger * supposed to be sorted. 0xfffffff0 and higher are not valid 69103998195SJoerg Sonnenberger */ 69203998195SJoerg Sonnenberger for (i = 0; i < udfmp->s_table->rt_l; i++) { 69303998195SJoerg Sonnenberger udfmp->s_table_entries = i; 69403998195SJoerg Sonnenberger if (udfmp->s_table->entries[i].org >= 0xfffffff0) 69503998195SJoerg Sonnenberger break; 69603998195SJoerg Sonnenberger } 69703998195SJoerg Sonnenberger } 69803998195SJoerg Sonnenberger 69903998195SJoerg Sonnenberger return(0); 70003998195SJoerg Sonnenberger } 701