darwin-xnu/bsd/isofs/cd9660/cd9660_vfsops.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22/*      $NetBSD: cd9660_vfsops.c,v 1.18 1995/03/09 12:05:36 mycroft Exp $       */
  23
  24/*-
  25 * Copyright (c) 1994
  26 *      The Regents of the University of California.  All rights reserved.
  27 *
  28 * This code is derived from software contributed to Berkeley
  29 * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
  30 * Support code is derived from software contributed to Berkeley
  31 * by Atsushi Murai (amurai@spec.co.jp).
  32 *
  33 * Redistribution and use in source and binary forms, with or without
  34 * modification, are permitted provided that the following conditions
  35 * are met:
  36 * 1. Redistributions of source code must retain the above copyright
  37 *    notice, this list of conditions and the following disclaimer.
  38 * 2. Redistributions in binary form must reproduce the above copyright
  39 *    notice, this list of conditions and the following disclaimer in the
  40 *    documentation and/or other materials provided with the distribution.
  41 * 3. All advertising materials mentioning features or use of this software
  42 *    must display the following acknowledgement:
  43 *      This product includes software developed by the University of
  44 *      California, Berkeley and its contributors.
  45 * 4. Neither the name of the University nor the names of its contributors
  46 *    may be used to endorse or promote products derived from this software
  47 *    without specific prior written permission.
  48 *
  49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  52 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  59 * SUCH DAMAGE.
  60 *
  61 *      @(#)cd9660_vfsops.c     8.9 (Berkeley) 12/5/94
  62 */
  63
  64#include <sys/param.h>
  65#include <sys/systm.h>
  66#include <sys/vnode_internal.h>
  67#include <sys/mount.h>
  68#include <sys/namei.h>
  69#include <sys/proc.h>
  70#include <sys/kauth.h>
  71#include <sys/kernel.h>
  72#include <miscfs/specfs/specdev.h>
  73#include <sys/buf.h>
  74#include <sys/file.h>
  75#include <sys/ioctl.h>
  76#include <sys/disk.h>
  77#include <sys/errno.h>
  78#include <sys/malloc.h>
  79#include <sys/stat.h>
  80#include <sys/ubc.h>
  81#include <sys/utfconv.h>
  82#include <architecture/byte_order.h>
  83
  84#include <isofs/cd9660/iso.h>
  85#include <isofs/cd9660/iso_rrip.h>
  86#include <isofs/cd9660/cd9660_node.h>
  87#include <isofs/cd9660/cd9660_mount.h>
  88
  89/*
  90 * Minutes, Seconds, Frames (M:S:F)
  91 */
  92struct CDMSF {
  93        u_char   minute;
  94        u_char   second;
  95        u_char   frame;
  96};
  97
  98/*
  99 * Table Of Contents
 100 */
 101struct CDTOC_Desc {
 102        u_char        session;
 103        u_char        ctrl_adr;  /* typed to be machine and compiler independent */
 104        u_char        tno;
 105        u_char        point;
 106        struct CDMSF  address;
 107        u_char        zero;
 108        struct CDMSF  p;
 109};
 110
 111struct CDTOC {
 112        u_short            length;  /* in native cpu endian */
 113        u_char             first_session;
 114        u_char             last_session;
 115        struct CDTOC_Desc  trackdesc[1];
 116};
 117
 118#define MSF_TO_LBA(msf)         \
 119        (((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
 120
 121u_char isonullname[] = "\0";
 122
 123struct vfsops cd9660_vfsops = {
 124        cd9660_mount,
 125        cd9660_start,
 126        cd9660_unmount,
 127        cd9660_root,
 128        NULL,                   /* quotactl */
 129        cd9660_vfs_getattr,
 130        cd9660_sync,
 131        cd9660_vget,
 132        cd9660_fhtovp,
 133        cd9660_vptofh,
 134        cd9660_init,
 135        cd9660_sysctl
 136};
 137
 138/*
 139 * Called by vfs_mountroot when iso is going to be mounted as root.
 140 *
 141 * Name is updated by mount(8) after booting.
 142 */
 143#define ROOTNAME        "root_device"
 144
 145static int iso_mountfs(struct vnode *devvp, struct mount *mp, struct user_iso_args *argp,
 146                       vfs_context_t context);
 147
 148static void DRGetTypeCreatorAndFlags(
 149                                struct iso_mnt * theMountPointPtr,
 150                                struct iso_directory_record * theDirRecPtr, 
 151                                u_int32_t * theTypePtr, 
 152                                u_int32_t * theCreatorPtr, 
 153                                u_int16_t * theFlagsPtr);
 154
 155int
 156cd9660_mountroot(mount_t mp, vnode_t rvp, vfs_context_t context)
 157{
 158        int     error;
 159        struct user_iso_args args;
 160
 161        args.flags = ISOFSMNT_ROOT;
 162        args.ssector = 0;
 163        args.toc_length = 0;
 164        args.toc = USER_ADDR_NULL;
 165
 166        if ((error = iso_mountfs(rvp, mp, &args, context)))
 167                return (error);
 168
 169        (void)cd9660_statfs(mp, vfs_statfs(mp), context);
 170
 171        return (0);
 172}
 173
 174/*
 175 * VFS Operations.
 176 *
 177 * mount system call
 178 */
 179int
 180cd9660_mount(mount_t mp, vnode_t devvp, user_addr_t data, vfs_context_t context)
 181{
 182        struct user_iso_args args;
 183        int error;
 184        struct iso_mnt *imp = NULL;
 185
 186        if (vfs_context_is64bit(context)) {
 187                error = copyin(data, (caddr_t)&args, sizeof (args));
 188        }
 189        else {
 190                struct iso_args temp;
 191                error = copyin(data, (caddr_t)&temp, sizeof (temp));
 192                args.flags = temp.flags;
 193                args.ssector = temp.ssector;
 194                args.toc_length = temp.toc_length;
 195                args.toc = CAST_USER_ADDR_T(temp.toc);
 196        }
 197        if (error)
 198                return (error);
 199        
 200        if (vfs_isrdwr(mp))
 201                return (EROFS);
 202
 203        /*
 204         * If updating, check whether changing from read-only to
 205         * read/write; if there is no device name, that's all we do.
 206         */
 207        if (vfs_isupdate(mp)) {
 208                imp = VFSTOISOFS(mp);
 209                if (devvp == 0)
 210                        return (0);
 211        }
 212        if ( !vfs_isupdate(mp))
 213                error = iso_mountfs(devvp, mp, &args, context);
 214        else {
 215                if (devvp != imp->im_devvp)
 216                        error = EINVAL; /* needs translation */
 217        }
 218        if (error) {
 219                return (error);
 220        }
 221
 222        /* Indicate that we don't support volfs */
 223        vfs_clearflags(mp, MNT_DOVOLFS);
 224
 225        return (0);
 226}
 227
 228/*
 229 * Find the BSD device for the physical disk corresponding to the
 230 * mount point's device.  We use this physical device to read whole
 231 * (2352 byte) sectors from the CD to get the content for the video
 232 * files (tracks).
 233 *
 234 * The "path" argument is the path to the block device that the volume
 235 * is being mounted on (args.fspec).  It should be of the form:
 236 *      /dev/disk1s0
 237 * where the last "s0" part is stripped off to determine the physical
 238 * device's path.  It is assumed to be in user memory.
 239 */
 240static struct vnode *
 241cd9660_phys_device(mount_t mp, vfs_context_t context)
 242{
 243        int err;
 244        char whole_path[64];    // path to "whole" device
 245        char *s, *saved;
 246        struct nameidata nd;
 247        struct vnode *result;
 248        struct vfsstatfs * sfs;
 249        
 250        sfs = vfs_statfs(mp);
 251        result = NULL;
 252
 253        if (strlen(sfs->f_mntfromname) >= sizeof(whole_path))
 254                return (NULL);
 255
 256        /* Make a copy of the mount from name, then remove trailing "s...". */
 257        strncpy(whole_path, sfs->f_mntfromname, sizeof(whole_path)-1); 
 258        
 259        /*
 260         * I would use strrchr or rindex here, but those are declared __private_extern__,
 261         * and can't be used across component boundaries at this time.
 262         */
 263        for (s=whole_path, saved=NULL; *s; ++s)
 264                if (*s == 's')
 265                        saved = s;
 266        *saved = '\0';
 267
 268        /* Lookup the "whole" device. */
 269        NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, CAST_USER_ADDR_T(whole_path), context);
 270        err = namei(&nd);
 271        if (err) {
 272                printf("isofs: Cannot find physical device: %s\n", whole_path);
 273                goto done;
 274        }
 275        nameidone(&nd);
 276
 277        /* Open the "whole" device. */
 278        err = VNOP_OPEN(nd.ni_vp, FREAD, context);
 279        if (err) {
 280                vnode_put(nd.ni_vp);
 281                printf("isofs: Cannot open physical device: %s\n", whole_path);
 282                goto done;
 283        }
 284        result = nd.ni_vp;
 285done:
 286        return result;
 287}
 288
 289
 290/*
 291 * See if the given CD-ROM XA disc appears to be a Video CD
 292 * (version < 2.0; so, not SVCD).  If so, fill in the extent
 293 * information for the MPEGAV directory, set the VCD flag,
 294 * and return true.
 295 */
 296static int
 297cd9660_find_video_dir(struct iso_mnt *isomp)
 298{
 299        int result, err;
 300        struct vnode *rvp = NULL;
 301        struct vnode *videovp = NULL;
 302        struct componentname cn;
 303        struct vfs_context context;
 304        char dirname[] = "MPEGAV";
 305        
 306        result = 0;             /* Assume not a video CD */
 307        
 308        err = cd9660_root(isomp->im_mountp, &rvp, NULL);
 309        if (err) {
 310                printf("cd9660_find_video_dir: cd9660_root failed (%d)\n", err);
 311                return 0;       /* couldn't find video dir */
 312        }
 313        
 314        context.vc_proc = current_proc();
 315        context.vc_ucred = kauth_cred_get();
 316
 317        cn.cn_nameiop = LOOKUP;
 318        cn.cn_flags = ISLASTCN;
 319        cn.cn_context = &context;
 320        cn.cn_pnbuf = dirname;
 321        cn.cn_pnlen = sizeof(dirname)-1;
 322        cn.cn_nameptr = cn.cn_pnbuf;
 323        cn.cn_namelen = cn.cn_pnlen;
 324        
 325        err = VNOP_LOOKUP(rvp, &videovp, &cn, &context);
 326        if (err == 0) {
 327                struct iso_node *ip = VTOI(videovp);
 328                result = 1;             /* Looks like video CD */
 329                isomp->video_dir_start = ip->iso_start;
 330                isomp->video_dir_end = ip->iso_start + (ip->i_size >> isomp->im_bshift);
 331                isomp->im_flags2 |= IMF2_IS_VCD;
 332
 333                vnode_put(videovp);
 334        }
 335        vnode_put(rvp);
 336        
 337        return result;
 338}
 339
 340/*
 341 * Common code for mount and mountroot
 342 */
 343static int
 344iso_mountfs(devvp, mp, argp, context)
 345        register struct vnode *devvp;
 346        struct mount *mp;
 347        struct user_iso_args *argp;
 348        vfs_context_t context;
 349{
 350        struct proc *p;
 351        register struct iso_mnt *isomp = (struct iso_mnt *)0;
 352        struct buf *bp = NULL;
 353        struct buf *pribp = NULL, *supbp = NULL;
 354        dev_t dev = vnode_specrdev(devvp);
 355        int error = EINVAL;
 356        int breaderr = 0;
 357        u_long iso_bsize;
 358        int iso_blknum;
 359        int joliet_level;
 360        struct iso_volume_descriptor *vdp = NULL;
 361        struct iso_primary_descriptor *pri = NULL;
 362        struct iso_primary_descriptor *sup = NULL;
 363        struct iso_directory_record *rootp;
 364        int logical_block_size;
 365        u_int8_t vdtype;
 366        int blkoff = argp->ssector;
 367        
 368        if (vfs_isrdwr(mp))
 369                return (EROFS);
 370
 371        /* This is the "logical sector size".  The standard says this
 372         * should be 2048 or the physical sector size on the device,
 373         * whichever is greater.  For now, we'll just use a constant.
 374         */
 375        iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
 376
 377        /* tell IOKit that we're assuming 2K sectors */
 378        if ((error = VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
 379             (caddr_t)&iso_bsize, FWRITE, context)))
 380                return (error);
 381
 382        joliet_level = 0;
 383        for (iso_blknum = 16 + blkoff; iso_blknum < (100 + blkoff); iso_blknum++) {
 384                if ((error = (int)buf_bread(devvp, (daddr64_t)((unsigned)iso_blknum), iso_bsize, NOCRED, &bp))) {
 385                        if (bp) {
 386                                buf_markaged(bp);
 387                                buf_brelse(bp);
 388                                bp = NULL;
 389                        }
 390                        breaderr = error;
 391                        printf("iso_mountfs: buf_bread error %d reading block %d\n", error, iso_blknum);
 392                        continue;
 393                }
 394
 395                vdp = (struct iso_volume_descriptor *)buf_dataptr(bp);
 396                if (bcmp (vdp->volume_desc_id, ISO_STANDARD_ID, sizeof(vdp->volume_desc_id)) != 0) {
 397#ifdef DEBUG
 398                        printf("cd9660_vfsops.c: iso_mountfs: "
 399                                        "Invalid ID in volume desciptor.\n");
 400#endif
 401                        /* There should be a primary volume descriptor followed by any
 402                         * secondary volume descriptors, then an end volume descriptor.
 403                         * Some discs are mastered without an end volume descriptor or
 404                         * they have the type field set and the volume descriptor ID is
 405                         * not set. If we at least found a primary volume descriptor,
 406                         * mount the disc.
 407                         */
 408                        if (pri != NULL)
 409                                break;
 410                        
 411                        error = EINVAL;
 412                        goto out;
 413                }
 414                
 415                vdtype = isonum_711 (vdp->type);
 416                if (vdtype == ISO_VD_END) 
 417                        break;
 418
 419                if (vdtype == ISO_VD_PRIMARY) {
 420                        if (pribp == NULL) {
 421                                pribp = bp;
 422                                bp = NULL;
 423                                pri = (struct iso_primary_descriptor *)vdp;
 424                        }
 425                } else if(vdtype == ISO_VD_SUPPLEMENTARY) {
 426                        if (supbp == NULL) {
 427                                supbp = bp;
 428                                bp = NULL;
 429                                sup = (struct iso_primary_descriptor *)vdp;
 430
 431                                if ((argp->flags & ISOFSMNT_NOJOLIET) == 0) {
 432                                        /*
 433                                         * some Joliet CDs are "out-of-spec and don't correctly
 434                                         * set the SVD flags. We ignore the flags and rely soely
 435                                         * on the escape_seq
 436                                         */
 437                                        if (bcmp(sup->escape_seq, ISO_UCS2_Level_1, 3) == 0)
 438                                                joliet_level = 1;
 439                                        else if (bcmp(sup->escape_seq, ISO_UCS2_Level_2, 3) == 0)
 440                                                joliet_level = 2;
 441                                        else if (bcmp(sup->escape_seq, ISO_UCS2_Level_3, 3) == 0)
 442                                                joliet_level = 3;
 443                                }
 444                        }
 445                }
 446
 447                if (bp) {
 448                        buf_markaged(bp);
 449                        buf_brelse(bp);
 450                        bp = NULL;
 451                }
 452        }
 453
 454        if (bp) {
 455                buf_markaged(bp);
 456                buf_brelse(bp);
 457                bp = NULL;
 458        }
 459        
 460        if (pri == NULL) {
 461                if (breaderr)
 462                        error = breaderr;
 463                else
 464                        error = EINVAL;
 465                goto out;
 466        }
 467        
 468        logical_block_size = isonum_723 (pri->logical_block_size);
 469        
 470        if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
 471            || (logical_block_size & (logical_block_size - 1)) != 0) {
 472                error = EINVAL;
 473                goto out;
 474        }
 475        
 476        rootp = (struct iso_directory_record *)pri->root_directory_record;
 477        
 478        MALLOC(isomp, struct iso_mnt *, sizeof *isomp, M_ISOFSMNT, M_WAITOK);
 479        bzero((caddr_t)isomp, sizeof *isomp);
 480        isomp->im_sector_size = ISO_DEFAULT_BLOCK_SIZE;
 481        isomp->logical_block_size = logical_block_size;
 482        isomp->volume_space_size = isonum_733 (pri->volume_space_size);
 483        /*
 484         * Since an ISO9660 multi-session CD can also access previous
 485         * sessions, we have to include them into the space consider-
 486         * ations.  This doesn't yield a very accurate number since
 487         * parts of the old sessions might be inaccessible now, but we
 488         * can't do much better.  This is also important for the NFS
 489         * filehandle validation.
 490         */
 491        isomp->volume_space_size += blkoff;
 492        bcopy (rootp, isomp->root, sizeof isomp->root);
 493        isomp->root_extent = isonum_733 (rootp->extent);
 494        isomp->root_size = isonum_733 (rootp->size);
 495
 496        /*
 497         * getattrlist wants the volume name, create date and modify date
 498         */
 499
 500        /* Remove any trailing white space */
 501        if ( strlen(pri->volume_id) ) {
 502                char            *myPtr;
 503
 504                myPtr = pri->volume_id + strlen( pri->volume_id ) - 1;
 505                while ( *myPtr == ' ' && myPtr >= pri->volume_id ) {
 506                        *myPtr = 0x00;
 507                        myPtr--;
 508                }
 509        }
 510
 511        if (pri->volume_id[0] == 0)
 512                strcpy(isomp->volume_id, ISO_DFLT_VOLUME_ID);
 513        else
 514                bcopy(pri->volume_id, isomp->volume_id, sizeof(isomp->volume_id));
 515        cd9660_tstamp_conv17(pri->creation_date, &isomp->creation_date);
 516        cd9660_tstamp_conv17(pri->modification_date, &isomp->modification_date);
 517
 518        /* See if this is a CD-XA volume */
 519        if (bcmp( pri->CDXASignature, ISO_XA_ID,
 520                        sizeof(pri->CDXASignature) ) == 0 ) {
 521                isomp->im_flags2 |= IMF2_IS_CDXA;
 522        }
 523
 524        isomp->im_bmask = logical_block_size - 1;
 525        isomp->im_bshift = 0;
 526        while ((1 << isomp->im_bshift) < isomp->logical_block_size)
 527                isomp->im_bshift++;
 528
 529        buf_markaged(pribp);
 530        buf_brelse(pribp);
 531        pribp = NULL;
 532
 533        vfs_setfsprivate(mp, (void *)isomp);
 534        vfs_statfs(mp)->f_fsid.val[0] = (long)dev;
 535        vfs_statfs(mp)->f_fsid.val[1] = vfs_typenum(mp);
 536        vfs_setmaxsymlen(mp, 0);
 537        vfs_setflags(mp, MNT_LOCAL);
 538
 539        isomp->im_mountp = mp;
 540        isomp->im_dev = dev;
 541        isomp->im_devvp = devvp;        
 542
 543        /*
 544         * If the logical block size is not 2K then we must
 545         * set the block device's physical block size to this
 546         * disc's logical block size.
 547         *
 548         */
 549        if (logical_block_size != iso_bsize) {
 550                iso_bsize = logical_block_size;
 551                if ((error = VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
 552                     (caddr_t)&iso_bsize, FWRITE, context)))
 553                        goto out;
 554        }
 555        
 556        /* Check the Rock Ridge Extention support */
 557        if (!(argp->flags & ISOFSMNT_NORRIP)) {
 558                if ( (error = (int)buf_bread(isomp->im_devvp,
 559                                             (daddr64_t)((unsigned)((isomp->root_extent + isonum_711(rootp->ext_attr_length)))),
 560                                             isomp->logical_block_size, NOCRED, &bp)) ) {
 561
 562                        printf("iso_mountfs: buf_bread error %d reading block %d\n",
 563                           error, isomp->root_extent + isonum_711(rootp->ext_attr_length));
 564                        argp->flags |= ISOFSMNT_NORRIP;
 565                        goto skipRRIP;
 566                }
 567                rootp = (struct iso_directory_record *)buf_dataptr(bp);
 568                
 569                if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
 570                        argp->flags  |= ISOFSMNT_NORRIP;
 571                } else {
 572                        argp->flags  &= ~ISOFSMNT_GENS;
 573                }
 574                
 575                /*
 576                 * The contents are valid,
 577                 * but they will get reread as part of another vnode, so...
 578                 */
 579                buf_markaged(bp);
 580                buf_brelse(bp);
 581                bp = NULL;
 582        }
 583skipRRIP:
 584
 585        isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
 586                                         ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET);
 587
 588        switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
 589        default:
 590                isomp->iso_ftype = ISO_FTYPE_DEFAULT;
 591                break;
 592        case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
 593                isomp->iso_ftype = ISO_FTYPE_9660;
 594                break;
 595        case 0:
 596                isomp->iso_ftype = ISO_FTYPE_RRIP;
 597                break;
 598        }
 599        
 600        /* Decide whether to use the Joliet descriptor */
 601
 602        if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level != 0) {
 603                char vol_id[32];
 604                int i, convflags;
 605                size_t convbytes;
 606                u_int16_t *uchp;
 607                
 608                /*
 609                 * On Joliet CDs use the UCS-2 volume identifier.
 610                 *
 611                 * This name can have up to 16 UCS-2 chars.
 612                 */
 613                convflags = UTF_DECOMPOSED;
 614                if (BYTE_ORDER != BIG_ENDIAN)
 615                        convflags |= UTF_REVERSE_ENDIAN;
 616                uchp = (u_int16_t *)sup->volume_id;
 617                for (i = 0; i < 16 && uchp[i]; ++i);
 618                if ((utf8_encodestr((u_int16_t *)sup->volume_id, (i * 2), vol_id,
 619                        &convbytes, sizeof(vol_id), 0, convflags) == 0)
 620                        && convbytes && (vol_id[0] != ' ')) {
 621                        char * strp;
 622
 623                        /* Remove trailing spaces */
 624                        strp = vol_id + convbytes - 1;
 625                        while (strp > vol_id && *strp == ' ')
 626                                *strp-- = '\0';
 627                        bcopy(vol_id, isomp->volume_id, convbytes + 1);
 628                }
 629
 630                rootp = (struct iso_directory_record *)
 631                        sup->root_directory_record;
 632                bcopy (rootp, isomp->root, sizeof isomp->root);
 633                isomp->root_extent = isonum_733 (rootp->extent);
 634                isomp->root_size = isonum_733 (rootp->size);
 635                buf_markaged(supbp);
 636                isomp->iso_ftype = ISO_FTYPE_JOLIET;
 637        }
 638
 639        if (supbp) {
 640                buf_brelse(supbp);
 641                supbp = NULL;
 642        }
 643
 644        /* If there was a TOC in the arguments, copy it in. */
 645        if (argp->flags & ISOFSMNT_TOC) {
 646                MALLOC(isomp->toc, struct CDTOC *, argp->toc_length, M_ISOFSMNT, M_WAITOK);
 647                if ((error = copyin(argp->toc, isomp->toc, argp->toc_length)))
 648                        goto out;
 649        }
 650
 651        /* See if this could be a Video CD */
 652        if ((isomp->im_flags2 & IMF2_IS_CDXA) && cd9660_find_video_dir(isomp)) {
 653                /* Get the 2352-bytes-per-block device. */
 654                isomp->phys_devvp = cd9660_phys_device(mp, context);
 655        }
 656
 657        /* Fill the default statfs information */
 658        (void) cd9660_statfs(mp, vfs_statfs(mp), context);
 659
 660        return (0);
 661out:
 662        if (bp)
 663                buf_brelse(bp);
 664        if (pribp)
 665                buf_brelse(pribp);
 666        if (supbp)
 667                buf_brelse(supbp);
 668
 669        if (isomp) {
 670                if (isomp->toc)
 671                        FREE((caddr_t)isomp->toc, M_ISOFSMNT);
 672                FREE((caddr_t)isomp, M_ISOFSMNT);
 673
 674                vfs_setfsprivate(mp, (void *)0);
 675        }
 676        return (error);
 677}
 678
 679/*
 680 * Make a filesystem operational.
 681 * Nothing to do at the moment.
 682 */
 683/* ARGSUSED */
 684int
 685cd9660_start(__unused struct mount *mp, __unused int flags,
 686             __unused vfs_context_t context)
 687{
 688        return (0);
 689}
 690
 691/*
 692 * unmount system call
 693 */
 694int
 695cd9660_unmount(struct mount *mp, int mntflags, vfs_context_t context)
 696{
 697        register struct iso_mnt *isomp;
 698        int error, flags = 0;
 699        int force = 0;
 700        
 701        if ( (mntflags & MNT_FORCE) ) {
 702                flags |= FORCECLOSE;
 703                force = 1;
 704        }
 705
 706        if ( (error = vflush(mp, NULLVP, flags)) && !force )
 707                return (error);
 708
 709        isomp = VFSTOISOFS(mp);
 710
 711#ifdef  ISODEVMAP
 712        if (isomp->iso_ftype == ISO_FTYPE_RRIP)
 713                iso_dunmap(isomp->im_dev);
 714#endif
 715        if (isomp->phys_devvp) {
 716                error = VNOP_CLOSE(isomp->phys_devvp, FREAD, context);
 717                if (error && !force)
 718                        return error;
 719                vnode_put(isomp->phys_devvp);
 720        }
 721
 722        if (isomp->toc)
 723                FREE((caddr_t)isomp->toc, M_ISOFSMNT);
 724        FREE((caddr_t)isomp, M_ISOFSMNT);
 725
 726        return (0);
 727}
 728
 729/*
 730 * Return root of a filesystem
 731 */
 732int
 733cd9660_root(struct mount *mp, struct vnode **vpp, __unused vfs_context_t context)
 734{
 735        struct iso_mnt *imp = VFSTOISOFS(mp);
 736        struct iso_directory_record *dp =
 737                (struct iso_directory_record *)imp->root;
 738        ino_t ino = isodirino(dp, imp);
 739
 740        /*
 741         * With RRIP we must use the `.' entry of the root directory.
 742         * Simply tell vget, that it's a relocated directory.
 743         */
 744        return (cd9660_vget_internal(mp, ino, vpp, NULL, NULL,
 745                imp->iso_ftype == ISO_FTYPE_RRIP, dp, current_proc()));
 746}
 747
 748/*
 749 * Get file system statistics.
 750 */
 751/* ARGSUSED */
 752int
 753cd9660_statfs(struct mount *mp, register struct vfsstatfs *sbp,
 754              __unused vfs_context_t context)
 755{
 756        register struct iso_mnt *isomp;
 757        
 758        isomp = VFSTOISOFS(mp);
 759
 760#if 0
 761#ifdef COMPAT_09
 762        sbp->f_type = 5;
 763#else
 764        sbp->f_type = 0;
 765#endif
 766#endif
 767        sbp->f_bsize = (uint32_t)isomp->logical_block_size;
 768        sbp->f_iosize = (size_t)sbp->f_bsize;   /* XXX */
 769        sbp->f_blocks = (uint64_t)((unsigned long)isomp->volume_space_size);
 770        sbp->f_bfree = (uint64_t)0; /* total free blocks */
 771        sbp->f_bavail = (uint64_t)0; /* blocks free for non superuser */
 772        sbp->f_files =  (uint64_t)0; /* total files */
 773        sbp->f_ffree = (uint64_t)0; /* free file nodes */
 774        sbp->f_fstypename[(MFSTYPENAMELEN - 1)] = '\0';
 775
 776        /*
 777         * Subtypes (flavors) for ISO 9660
 778         *   0:   ISO-9660
 779         *   1:   ISO-9660 (Joliet) 
 780         *   2:   ISO-9660 (Rockridge) 
 781         */
 782        if (isomp->iso_ftype == ISO_FTYPE_JOLIET)
 783                sbp->f_fssubtype = 1;
 784        else if (isomp->iso_ftype == ISO_FTYPE_RRIP)
 785                sbp->f_fssubtype = 2;
 786        else
 787                sbp->f_fssubtype = 0;
 788
 789        /* DO NOT use the first spare for flags; it's been reassigned for another use: */
 790        /* sbp->f_spare[0] = isomp->im_flags; */
 791
 792        return (0);
 793}
 794
 795int cd9660_vfs_getattr(struct mount *mp, struct vfs_attr *fsap, vfs_context_t context)
 796{
 797        struct iso_mnt *imp;
 798        struct vfsstatfs *stats = vfs_statfs(mp);
 799
 800        imp = VFSTOISOFS(mp);
 801
 802        /*
 803         * We don't know reasonable values for f_objcount, f_filecount,
 804         * f_dircount, f_maxobjcount so don't bother making up (poor)
 805         * numbers like 10.3.x and earlier did.
 806         */
 807        
 808        VFSATTR_RETURN(fsap, f_iosize, stats->f_iosize);
 809        VFSATTR_RETURN(fsap, f_blocks, stats->f_blocks);
 810        VFSATTR_RETURN(fsap, f_bfree,  stats->f_bfree);
 811        VFSATTR_RETURN(fsap, f_bavail, stats->f_bavail);
 812        VFSATTR_RETURN(fsap, f_bused,  stats->f_blocks);
 813        
 814        /* We don't have file counts, so don't return them */
 815        
 816        /* f_fsid and f_owner should be handled by VFS */
 817        
 818        /* We don't have a value for f_uuid */
 819        
 820        if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) {
 821                fsap->f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] =
 822                        (imp->iso_ftype == ISO_FTYPE_RRIP ? VOL_CAP_FMT_SYMBOLICLINKS : 0) |
 823                        (imp->iso_ftype == ISO_FTYPE_RRIP ? VOL_CAP_FMT_HARDLINKS : 0) |
 824                        (imp->iso_ftype == ISO_FTYPE_RRIP || imp->iso_ftype == ISO_FTYPE_JOLIET
 825                                ? VOL_CAP_FMT_CASE_SENSITIVE : 0) |
 826                        VOL_CAP_FMT_CASE_PRESERVING |
 827                        VOL_CAP_FMT_FAST_STATFS;
 828                fsap->f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] =
 829                        VOL_CAP_INT_ATTRLIST |
 830                        VOL_CAP_INT_NFSEXPORT;
 831                fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
 832                fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
 833                
 834                fsap->f_capabilities.valid[VOL_CAPABILITIES_FORMAT] =
 835                        VOL_CAP_FMT_PERSISTENTOBJECTIDS |
 836                        VOL_CAP_FMT_SYMBOLICLINKS |
 837                        VOL_CAP_FMT_HARDLINKS |
 838                        VOL_CAP_FMT_JOURNAL |
 839                        VOL_CAP_FMT_JOURNAL_ACTIVE |
 840                        VOL_CAP_FMT_NO_ROOT_TIMES |
 841                        VOL_CAP_FMT_SPARSE_FILES |
 842                        VOL_CAP_FMT_ZERO_RUNS |
 843                        VOL_CAP_FMT_CASE_SENSITIVE |
 844                        VOL_CAP_FMT_CASE_PRESERVING |
 845                        VOL_CAP_FMT_FAST_STATFS | 
 846                        VOL_CAP_FMT_2TB_FILESIZE;
 847                fsap->f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] =
 848                        VOL_CAP_INT_SEARCHFS |
 849                        VOL_CAP_INT_ATTRLIST |
 850                        VOL_CAP_INT_NFSEXPORT |
 851                        VOL_CAP_INT_READDIRATTR |
 852                        VOL_CAP_INT_EXCHANGEDATA |
 853                        VOL_CAP_INT_COPYFILE |
 854                        VOL_CAP_INT_ALLOCATE |
 855                        VOL_CAP_INT_VOL_RENAME |
 856                        VOL_CAP_INT_ADVLOCK |
 857                        VOL_CAP_INT_FLOCK;
 858                fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0;
 859                fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0;
 860                
 861                VFSATTR_SET_SUPPORTED(fsap, f_capabilities);
 862        }
 863        
 864        if (VFSATTR_IS_ACTIVE(fsap, f_attributes)) {
 865                /*
 866                 * VFS should really set these based on the vfs_attr and vnop_attr
 867                 * fields the file system supports, combined with the conversions
 868                 * VFS has implemented.
 869                 */
 870
 871                fsap->f_attributes.validattr.commonattr = ATTR_CMN_VALIDMASK;
 872        fsap->f_attributes.validattr.volattr = ATTR_VOL_VALIDMASK;
 873        fsap->f_attributes.validattr.dirattr = ATTR_DIR_VALIDMASK;
 874        fsap->f_attributes.validattr.fileattr = ATTR_FILE_VALIDMASK;
 875        fsap->f_attributes.validattr.forkattr = ATTR_FORK_VALIDMASK;
 876
 877                fsap->f_attributes.nativeattr.commonattr = ATTR_CMN_VALIDMASK;
 878        fsap->f_attributes.nativeattr.volattr = ATTR_VOL_VALIDMASK;
 879        fsap->f_attributes.nativeattr.dirattr = ATTR_DIR_VALIDMASK;
 880        fsap->f_attributes.nativeattr.fileattr = ATTR_FILE_VALIDMASK;
 881        fsap->f_attributes.nativeattr.forkattr = ATTR_FORK_VALIDMASK;
 882
 883                VFSATTR_SET_SUPPORTED(fsap, f_attributes);
 884        }
 885        
 886        VFSATTR_RETURN(fsap, f_create_time, imp->creation_date);
 887        VFSATTR_RETURN(fsap, f_modify_time, imp->modification_date);
 888        /* No explicit access time, so let VFS pick a default value */
 889        /* No explicit backup time, so let VFS pick a default value */
 890        
 891        return 0;
 892}
 893
 894/* ARGSUSED */
 895int
 896cd9660_sync(__unused struct mount *mp, __unused int waitfor,
 897            __unused vfs_context_t context)
 898{
 899
 900        return (0);
 901}
 902
 903/*
 904 * File handle to vnode
 905 *
 906 * Have to be really careful about stale file handles:
 907 * - check that the inode number is in range
 908 * - call iget() to get the locked inode
 909 * - check for an unallocated inode (i_mode == 0)
 910 * - check that the generation number matches
 911 */
 912
 913struct ifid {
 914        int     ifid_ino;
 915        long    ifid_start;
 916};
 917
 918/* ARGSUSED */
 919int
 920cd9660_fhtovp(mount_t mp, int fhlen, unsigned char *fhp, vnode_t *vpp, vfs_context_t context)
 921{
 922        struct ifid *ifhp = (struct ifid *)fhp;
 923        register struct iso_node *ip;
 924        struct vnode *nvp;
 925        int error;
 926        
 927        if (fhlen < (int)sizeof(struct ifid))
 928                return (EINVAL);
 929
 930#ifdef  ISOFS_DBG
 931        printf("fhtovp: ino %d, start %ld\n",
 932               ifhp->ifid_ino, ifhp->ifid_start);
 933#endif
 934        
 935        if ( (error = VFS_VGET(mp, (ino64_t)ifhp->ifid_ino, &nvp, context)) ) {
 936                *vpp = NULLVP;
 937                return (error);
 938        }
 939        ip = VTOI(nvp);
 940        if (ip->inode.iso_mode == 0) {
 941                vnode_put(nvp);
 942                *vpp = NULLVP;
 943                return (ESTALE);
 944        }
 945        *vpp = nvp;
 946        return (0);
 947}
 948
 949/*
 950 * Scan the TOC for the track which contains the given sector.
 951 *
 952 * If there is no matching track, or no TOC, then return -1.
 953 */
 954static int
 955cd9660_track_for_sector(struct CDTOC *toc, u_int sector)
 956{
 957        int i, tracks, result;
 958        
 959        if (toc == NULL)
 960                return -1;
 961
 962        tracks = toc->length / sizeof(struct CDTOC_Desc);
 963        
 964        result = -1;            /* Sentinel in case we don't find the right track. */
 965        for (i=0; i<tracks; ++i) {
 966                if (toc->trackdesc[i].point < 100 && MSF_TO_LBA(toc->trackdesc[i].p) <= sector) {
 967                        result = toc->trackdesc[i].point;
 968                }
 969        }
 970        
 971        return result;
 972}
 973
 974/*
 975 * Determine whether the given node is really a video CD video
 976 * file.  Return non-zero if it appears to be a video file.
 977 */
 978static int
 979cd9660_is_video_file(struct iso_node *ip, struct iso_mnt *imp)
 980{
 981        int lbn;
 982        int track;
 983        
 984        /* Check whether this could really be a Video CD at all */
 985        if (((imp->im_flags2 & IMF2_IS_VCD) == 0) ||
 986                imp->phys_devvp == NULL ||
 987                imp->toc == NULL)
 988        {
 989                return 0;       /* Doesn't even look like VCD... */
 990        }
 991
 992        /* Make sure it is a file */
 993        if ((ip->inode.iso_mode & S_IFMT) != S_IFREG)
 994                return 0;       /* Not even a file... */
 995
 996        /*
 997         * And in the right directory.  This assumes the same inode
 998         * number convention that cd9660_vget_internal uses (that
 999         * part of the inode number is the block containing the
1000         * file's directory entry).
1001         */
1002        lbn = lblkno(imp, ip->i_number);
1003        if (lbn < imp->video_dir_start || lbn >= imp->video_dir_end)
1004                return 0;       /* Not in the correct directory */
1005        
1006        /*
1007         * If we get here, the file should be a video file, but
1008         * do a couple of extra sanity checks just to be sure.
1009         * First, verify the form of the name
1010         */
1011        if (strlen(ip->i_namep) != 11 ||                /* Wrong length? */
1012                bcmp(ip->i_namep+7, ".DAT", 4) ||       /* Wrong extension? */
1013                (bcmp(ip->i_namep, "AVSEQ", 5) &&       /* Wrong beginning? */
1014                 bcmp(ip->i_namep, "MUSIC", 5)))
1015        {
1016                return 0;       /* Invalid name format */
1017        }
1018        
1019        /*
1020         * Verify that AVSEQnn.DAT is in track #(nn+1).  This would
1021         * not be appropriate for Super Video CD, which allows
1022         * multiple sessions, so the track numbers might not
1023         * match up like this. 
1024         */
1025        track = (ip->i_namep[5] - '0') * 10 + ip->i_namep[6] - '0';
1026        if (track != (cd9660_track_for_sector(imp->toc, ip->iso_start) - 1))
1027        {
1028                return 0;       /* Wrong number in name */
1029        }
1030
1031        /* It must be a video file if we got here. */
1032        return 1;
1033}
1034
1035int
1036cd9660_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, __unused vfs_context_t context)
1037{
1038        /*
1039         * XXXX
1040         * It would be nice if we didn't always set the `relocated' flag
1041         * and force the extra read, but I don't want to think about fixing
1042         * that right now.
1043         */
1044
1045        return ( cd9660_vget_internal( mp, (ino_t)ino, vpp, NULL, NULL,
1046                                       0, (struct iso_directory_record *) 0, current_proc()) );
1047}
1048
1049int
1050cd9660_vget_internal(mount_t mp, ino_t ino, vnode_t *vpp, vnode_t dvp,
1051                     struct componentname *cnp, int relocated,
1052                     struct iso_directory_record *isodir, proc_t p)
1053{
1054        register struct iso_mnt *imp;
1055        struct iso_node *ip;
1056        buf_t   bp = NULL;
1057        vnode_t vp;
1058        dev_t   dev;
1059        int     error;
1060        struct vnode_fsparam vfsp;
1061        enum vtype vtype;
1062        int is_video_file = 0;
1063
1064        *vpp = NULLVP;
1065        imp  = VFSTOISOFS(mp);
1066        dev  = imp->im_dev;
1067#if 0
1068        /* Check for unmount in progress */
1069        if (mp->mnt_kern_flag & MNTK_UNMOUNT)
1070                return (EPERM);
1071#endif
1072
1073        MALLOC_ZONE(ip, struct iso_node *, sizeof(struct iso_node),
1074                    M_ISOFSNODE, M_WAITOK);
1075        /*
1076         * MALLOC_ZONE may block, so check for the inode being 
1077         * present in the hash after we get back...
1078         * we also assume that we're under a filesystem lock
1079         * so that we're not reentered between the ihashget and
1080         * the ihashins...
1081         */
1082        if ((*vpp = cd9660_ihashget(dev, ino, p)) != NULLVP) {
1083                FREE_ZONE(ip, sizeof(struct iso_node), M_ISOFSNODE);
1084                return (0);
1085        }
1086        bzero((caddr_t)ip, sizeof(struct iso_node));
1087
1088        ip->i_dev = dev;
1089        ip->i_number = ino;
1090        ip->i_namep = &isonullname[0];
1091        ip->i_mnt = imp;
1092        ip->i_devvp = imp->im_devvp;
1093
1094        SET(ip->i_flag, ISO_INALLOC);
1095        /*
1096         * Put it onto its hash chain and lock it so that other requests for
1097         * this inode will block if they arrive while we are sleeping waiting
1098         * for old data structures to be purged or for the contents of the
1099         * disk portion of this inode to be read.
1100         */
1101        cd9660_ihashins(ip);
1102
1103        if (isodir == 0) {
1104                int lbn, off;
1105
1106                lbn = lblkno(imp, ino);
1107
1108                if (lbn >= imp->volume_space_size) {
1109                        printf("fhtovp: lbn exceed volume space %d\n", lbn);
1110                        error = ESTALE;
1111                        goto errout;
1112                }
1113                off = blkoff(imp, ino);
1114
1115                if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
1116                        printf("fhtovp: crosses block boundary %d\n",
1117                                off + ISO_DIRECTORY_RECORD_SIZE);
1118                        error = ESTALE;
1119                        goto errout;
1120                }
1121        
1122                error = (int)buf_bread(imp->im_devvp, (daddr64_t)((unsigned)lbn),
1123                                       imp->logical_block_size, NOCRED, &bp);
1124                if (error) {
1125                        printf("fhtovp: buf_bread error %d\n",error);
1126                        goto errout;
1127                }
1128                isodir = (struct iso_directory_record *)(buf_dataptr(bp) + off);
1129
1130                if (off + isonum_711(isodir->length) > imp->logical_block_size) {
1131                        printf("fhtovp: directory crosses block boundary "
1132                                "%d[off=%d/len=%d]\n",
1133                                off +isonum_711(isodir->length), off,
1134                                isonum_711(isodir->length));
1135                        error = ESTALE;
1136                        goto errout;
1137                }
1138
1139                /*
1140                 * for directories we can get parentID from adjacent 
1141                 * parent directory record
1142                 */
1143                if ((isonum_711(isodir->flags) & directoryBit)
1144                                && (isodir->name[0] == 0)) {
1145                        struct iso_directory_record *pdp;
1146
1147                        pdp = (struct iso_directory_record *)
1148                                        ((char *)buf_dataptr(bp) + isonum_711(isodir->length));
1149                        if ((isonum_711(pdp->flags) & directoryBit)
1150                                        && (pdp->name[0] == 1))
1151                                ip->i_parent = isodirino(pdp, imp);
1152                }
1153        }
1154        if (relocated) {
1155                daddr64_t lbn;
1156
1157                if (bp) {
1158                        buf_brelse(bp);
1159                        bp = NULL;
1160                }
1161                /*
1162                 * On relocated directories we must
1163                 * read the `.' entry out of a dir.
1164                 */
1165                ip->iso_start = ino >> imp->im_bshift;
1166                /*
1167                 * caclulate the correct lbn to read block 0
1168                 * of this node... this used to be a cd9660_blkatoff, but
1169                 * that requires the vnode to already be 'cooked'... in
1170                 * the new world, we don't create a vnode until the inode
1171                 * has been fully initialized... cd9660_blkatoff generates
1172                 * a buf_bread for im_sector_size associated with the node's vp
1173                 * I'm replacing it with a buf_bread for the same size and from
1174                 * the same location on the disk, but associated with the devvp
1175                 */
1176                lbn = (daddr64_t)((unsigned)ip->iso_start) + 0;
1177
1178                if ((error = (int)buf_bread(imp->im_devvp, lbn, imp->im_sector_size, NOCRED, &bp)))
1179                        goto errout;
1180
1181                isodir = (struct iso_directory_record *)buf_dataptr(bp);
1182        }
1183
1184        /*
1185         * go get apple extensions to ISO directory record or use
1186         * defaults when there are no apple extensions.
1187         */
1188        if ( ((isonum_711( isodir->flags ) & directoryBit) == 0) &&
1189             (imp->iso_ftype != ISO_FTYPE_RRIP) ) {
1190                /* This is an ISO directory record for a file */
1191                DRGetTypeCreatorAndFlags(imp, isodir, &ip->i_FileType, 
1192                                         &ip->i_Creator, &ip->i_FinderFlags);
1193
1194                if (isonum_711(isodir->flags) & associatedBit)
1195                        ip->i_flag |= ISO_ASSOCIATED;
1196        }
1197
1198        /*
1199         * Shadow the ISO 9660 invisible state to the FinderInfo
1200         */
1201        if (isonum_711(isodir->flags) & existenceBit) {
1202                ip->i_FinderFlags |= fInvisibleBit;
1203        }
1204
1205        ip->iso_extent = isonum_733(isodir->extent);
1206        ip->i_size = isonum_733(isodir->size);
1207        ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
1208        /*
1209         * account for AppleDouble header
1210         */
1211        if (ip->i_flag & ISO_ASSOCIATED)
1212                ip->i_size += ADH_SIZE;
1213
1214        /*
1215         * if we have a valid name, fill in i_namep with UTF-8 name
1216         */
1217        if (isonum_711(isodir->name_len) != 0) {
1218                u_char *utf8namep;
1219                u_short namelen;
1220                ino_t inump = 0;
1221
1222                MALLOC(utf8namep, u_char *, ISO_RRIP_NAMEMAX + 1, M_TEMP, M_WAITOK);
1223                namelen = isonum_711(isodir->name_len);
1224
1225                switch (imp->iso_ftype) {
1226                case ISO_FTYPE_RRIP:
1227                        cd9660_rrip_getname(isodir, utf8namep, &namelen, &inump, imp);
1228                        break;
1229
1230                case ISO_FTYPE_JOLIET:
1231                        ucsfntrans((u_int16_t *)isodir->name, namelen,
1232                                   utf8namep, &namelen,
1233                                   isonum_711(isodir->flags) & directoryBit, ip->i_flag & ISO_ASSOCIATED);
1234                        break;
1235
1236                default:
1237                        isofntrans (isodir->name, namelen,
1238                                        utf8namep, &namelen,
1239                                        imp->iso_ftype == ISO_FTYPE_9660, ip->i_flag & ISO_ASSOCIATED);
1240                }
1241
1242                utf8namep[namelen] = '\0';
1243                MALLOC(ip->i_namep, u_char *, namelen + 1, M_TEMP, M_WAITOK);
1244                bcopy(utf8namep, ip->i_namep, namelen + 1);
1245                FREE(utf8namep, M_TEMP);
1246        }
1247
1248        /*
1249         * Setup time stamp, attribute
1250         */
1251        switch (imp->iso_ftype) {
1252        default:        /* ISO_FTYPE_9660 */
1253                {
1254                buf_t   bp2 = NULL;
1255                daddr64_t lbn;
1256                int     off;
1257
1258                if ((imp->im_flags & ISOFSMNT_EXTATT) && (off = isonum_711(isodir->ext_attr_length))) {
1259
1260                        lbn = (daddr64_t)((unsigned)ip->iso_start - off);
1261
1262                        if ((error = (int)buf_bread(imp->im_devvp, lbn, imp->im_sector_size, NOCRED, &bp2))) {
1263                                if (bp2)
1264                                        buf_brelse(bp2);
1265                                goto errout;
1266                        }
1267                } else
1268                        bp2 = NULL;
1269
1270                cd9660_defattr(isodir, ip, bp2);
1271                cd9660_deftstamp(isodir, ip, bp2);
1272
1273                if (bp2)
1274                        buf_brelse(bp2);
1275                break;
1276                }
1277        case ISO_FTYPE_RRIP:
1278                cd9660_rrip_analyze(isodir, ip, imp);
1279                break;
1280        }
1281        /*
1282         * See if this is a Video CD file.  If so, we must adjust the
1283         * length to account for larger sectors plus the RIFF header.
1284         * We also must substitute the vnop_read and vnop_pagein functions.
1285         *
1286         * The cd9660_is_video_file routine assumes that the inode has
1287         * been completely set up; it refers to several fields.
1288         *
1289         * This must be done before we release bp, because isodir
1290         * points into bp's data.
1291         */
1292        if (cd9660_is_video_file(ip, imp))
1293        {
1294                cd9660_xa_init(ip, isodir);
1295                
1296                is_video_file = 1;
1297        }
1298        if (ip->iso_extent == imp->root_extent) {
1299                ip->i_parent = 1;       /* root's parent is always 1 by convention */
1300                /* mode type must be S_IFDIR */
1301                ip->inode.iso_mode = (ip->inode.iso_mode & ~S_IFMT) | S_IFDIR;
1302        }
1303        vtype = IFTOVT(ip->inode.iso_mode);
1304#if !FIFO
1305        if (vtype == VFIFO) {
1306                error = ENOTSUP;
1307                goto errout;
1308        }
1309#endif
1310#ifdef  ISODEVMAP
1311        if (vtype == VCHR || vtype == VBLK) {
1312                struct iso_dnode *dp;
1313
1314                if (dp = iso_dmap(dev, ino, 0))
1315                        ip->inode.iso_rdev = dp->d_dev;
1316        }
1317#endif
1318        /*
1319         * create the associated vnode
1320         */
1321        //bzero(&vfsp, sizeof(struct vnode_fsparam));
1322        vfsp.vnfs_mp = mp;
1323        vfsp.vnfs_vtype = vtype;
1324        vfsp.vnfs_str = "cd9660";
1325        vfsp.vnfs_dvp = dvp;
1326        vfsp.vnfs_fsnode = ip;
1327        vfsp.vnfs_cnp = cnp;
1328
1329        if (is_video_file)
1330                vfsp.vnfs_vops = cd9660_cdxaop_p;
1331        else if (vtype == VFIFO )
1332                vfsp.vnfs_vops = cd9660_fifoop_p;
1333        else if (vtype == VBLK || vtype == VCHR)
1334                vfsp.vnfs_vops = cd9660_specop_p;
1335        else
1336                vfsp.vnfs_vops = cd9660_vnodeop_p;
1337                
1338        if (vtype == VBLK || vtype == VCHR)
1339                vfsp.vnfs_rdev = ip->inode.iso_rdev;
1340        else
1341                vfsp.vnfs_rdev = 0;
1342
1343        vfsp.vnfs_filesize = ip->i_size;
1344
1345        if (dvp && cnp && (cnp->cn_flags & MAKEENTRY))
1346                vfsp.vnfs_flags = 0;
1347        else
1348                vfsp.vnfs_flags = VNFS_NOCACHE;
1349
1350        /* Tag root directory */
1351        if (ip->iso_extent == imp->root_extent)
1352                vfsp.vnfs_markroot = 1;
1353        else    
1354                vfsp.vnfs_markroot = 0;
1355
1356        vfsp.vnfs_marksystem = 0;
1357
1358        if ( (error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &vp)) )
1359                goto errout;
1360
1361        ip->i_vnode = vp;
1362
1363        vnode_ref(ip->i_devvp);
1364        vnode_addfsref(vp);
1365        vnode_settag(vp, VT_ISOFS);
1366
1367        if (bp)
1368                buf_brelse(bp);
1369        *vpp = vp;
1370
1371        CLR(ip->i_flag, ISO_INALLOC);
1372
1373        if (ISSET(ip->i_flag, ISO_INWALLOC))
1374                wakeup(ip);
1375
1376        return (0);
1377
1378errout:
1379        if (bp)
1380                buf_brelse(bp);
1381        cd9660_ihashrem(ip);
1382
1383        if (ISSET(ip->i_flag, ISO_INWALLOC))
1384                wakeup(ip);
1385
1386        FREE_ZONE(ip, sizeof(struct iso_node), M_ISOFSNODE);
1387
1388        return (error);
1389}
1390
1391
1392/************************************************************************
1393 *
1394 *  Function:   DRGetTypeCreatorAndFlags
1395 *
1396 *  Purpose:    Set up the fileType, fileCreator and fileFlags
1397 *
1398 *  Returns:    none
1399 *
1400 *  Side Effects:       sets *theTypePtr, *theCreatorPtr, and *theFlagsPtr
1401 *
1402 *  Description:
1403 *
1404 *  Revision History:
1405 *      28 Jul 88       BL¡B    Added a new extension type of 6, which allows
1406 *                                              the specification of four of the finder flags.
1407 *                                              We let the creator of the disk just copy over
1408 *                                              the finder flags, but we only look at always
1409 *                                              switch launch, system, bundle, and locked bits.
1410 *      15 Aug 88       BL¡B    The Apple extensions to ISO 9660 implemented the
1411 *                                              padding field at the end of a directory record
1412 *                                              incorrectly.
1413 *      19 Jul 89       BG              Rewrote routine to handle the "new" Apple
1414 *                                              Extensions definition, as well as take into
1415 *                                              account the possibility of "other" definitions.
1416 *      02 Nov 89       BG              Corrected the 'AA' SystemUseID processing to
1417 *                                              check for SystemUseID == 2 (HFS).  Was incorrectly
1418 *                                              checking for SystemUseID == 1 (ProDOS) before.
1419 *      18 Mar 92       CMP             Fixed the check for whether len_fi was odd or even.
1420 *                                              Before it would always assume even for an XA record.
1421 *      26 Dec 97       jwc             Swiped from MacOS implementation of ISO 9660 CD-ROM
1422 *                                              support and modified to work in MacOSX file system.
1423 *
1424 *********************************************************************** */
1425 
1426static void
1427DRGetTypeCreatorAndFlags(       struct iso_mnt * theMountPointPtr,
1428                                                        struct iso_directory_record * theDirRecPtr, 
1429                                                        u_int32_t * theTypePtr, 
1430                                                        u_int32_t * theCreatorPtr, 
1431                                                        u_int16_t * theFlagsPtr )
1432{
1433        int                                     foundStuff;
1434        u_int32_t                       myType;
1435        u_int32_t                       myCreator;
1436        AppleExtension          *myAppleExtPtr;
1437        NewAppleExtension       *myNewAppleExtPtr;
1438        u_int16_t                       myFinderFlags;
1439        char                            *myPtr;
1440
1441        foundStuff = 1;
1442        myType = 0x3f3f3f3f;
1443        myCreator = 0x3f3f3f3f;
1444        myFinderFlags = 0;
1445        *theFlagsPtr = 0x0000;
1446
1447        /*
1448         * handle the fact that our original apple extensions didn't take
1449         * into account the padding byte on a file name
1450         */
1451
1452        myPtr = &theDirRecPtr->name[ (isonum_711(theDirRecPtr->name_len)) ];
1453        
1454        /* if string length is even, bump myPtr for padding byte */
1455        if ( ((isonum_711(theDirRecPtr->name_len)) & 0x01) == 0 )
1456                myPtr++;
1457        myAppleExtPtr = (AppleExtension *) myPtr;
1458
1459        /*
1460         * checking for whether or not the new 'AA' code is being 
1461         * called (and if so, correctly)
1462         */
1463        if ( (isonum_711(theDirRecPtr->length)) <= 
1464                 ISO_DIRECTORY_RECORD_SIZE + (isonum_711(theDirRecPtr->name_len)) ) {
1465                foundStuff = 0;
1466                goto DoneLooking;
1467        }
1468
1469        foundStuff = 0; /* now we default to *false* until we find a good one */
1470        myPtr = (char *) myAppleExtPtr;
1471
1472        if ( (theMountPointPtr->im_flags2 & IMF2_IS_CDXA) != 0 )
1473                myPtr += 14;/* add in CD-XA fixed record offset (tnx, Phillips) */
1474        myNewAppleExtPtr = (NewAppleExtension *) myPtr;
1475
1476        /*
1477         * Calculate the "real" end of the directory record information.
1478         *
1479         * Note: We always read the first 4 bytes of the System-Use data, so
1480         * adjust myPtr down so we don't read off the end of the directory!
1481         */
1482        myPtr = ((char *) theDirRecPtr) + (isonum_711(theDirRecPtr->length));
1483        myPtr -= sizeof(NewAppleExtension) - 1;
1484        while( (char *) myNewAppleExtPtr < myPtr )      /* end of directory buffer */
1485        {
1486                /*
1487                 *      If we get here, we can assume that ALL further entries in this
1488                 *      directory record are of the form:
1489                 *
1490                 *              struct OptionalSystemUse
1491                 *              {
1492                 *                      byte    Signature[2];
1493                 *                      byte    OSULength;
1494                 *                      byte    systemUseID;
1495                 *                      byte    fileType[4];            # only if HFS
1496                 *                      byte    fileCreator[4];         # only if HFS
1497                 *                      byte    finderFlags[2];         # only if HFS
1498                 *              };
1499                 *
1500                 *      This means that we can examine the Signature bytes to see
1501                 *      if they are 'AA' (the NEW Apple extension signature).
1502                 *      If they are, deal with them.  If they aren't,
1503                 *      the OSULength field will tell us how long this extension
1504                 *      info is (including the signature and length bytes) and that
1505                 *      will allow us to walk the OptionalSystemUse records until
1506                 *      we hit the end of them or run off the end of the 
1507                 *      directory record.
1508                 */
1509                u_char                          *myFromPtr, *myToPtr;
1510                union
1511                {
1512                        u_int32_t               fourchars;
1513                        u_char                  chars[4];
1514                } myChars;
1515
1516                if ( (myNewAppleExtPtr->signature[0] == 'A') &&
1517                        (myNewAppleExtPtr->signature[1] == 'A') ) {
1518                        if ( isonum_711(myNewAppleExtPtr->systemUseID) == 2 ) {
1519                                /* HFS */
1520                                foundStuff = 1;                 /* we got one! */
1521
1522                                myFromPtr = &myNewAppleExtPtr->fileType[0]; 
1523                                myToPtr = &myChars.chars[0];
1524                                *myToPtr++ = *myFromPtr++; 
1525                                *myToPtr++ = *myFromPtr++; 
1526                                *myToPtr++ = *myFromPtr++; 
1527                                *myToPtr = *myFromPtr;
1528                                myType = myChars.fourchars;     /* copy file type to user var */
1529
1530                                myFromPtr = &myNewAppleExtPtr->fileCreator[0]; 
1531                                myToPtr = &myChars.chars[0];
1532                                *myToPtr++ = *myFromPtr++; 
1533                                *myToPtr++ = *myFromPtr++; 
1534                                *myToPtr++ = *myFromPtr++; 
1535                                *myToPtr = *myFromPtr;
1536                                myCreator = myChars.fourchars;  /* copy creator to user var */
1537
1538                                myFromPtr = &myNewAppleExtPtr->finderFlags[0]; 
1539                                myToPtr = &myChars.chars[2];    /* *flags* is a short */
1540                                myChars.fourchars = 0; 
1541                                *myToPtr++ = *myFromPtr++; 
1542                                *myToPtr = *myFromPtr;
1543                                myFinderFlags = myChars.fourchars;
1544                                myFinderFlags &=
1545                                        ( fAlwaysBit | fSystemBit | fHasBundleBit | fLockedBit );
1546                                /* return Finder flags to user var */
1547                                *theFlagsPtr = (myFinderFlags | fInitedBit);
1548
1549                                break;          /* exit the loop */
1550                        }
1551                }
1552
1553                /*
1554                 *      Check to see if we have a reasonable OSULength value.
1555                 *      ZERO is not an acceptable value.  Nor is any value less than 4.
1556                 */
1557
1558                if ( (isonum_711(myNewAppleExtPtr->OSULength)) < 4 ) 
1559                        break;  /* not acceptable - get out! */
1560
1561                /* otherwise, step past this SystemUse record */
1562                (char *)myNewAppleExtPtr += (isonum_711(myNewAppleExtPtr->OSULength));
1563                
1564        } /* end of while loop */
1565
1566DoneLooking:
1567        if ( foundStuff != 0 ) {
1568                *theTypePtr    = myType;
1569                *theCreatorPtr = myCreator;
1570        } else {
1571                *theTypePtr = 0;
1572                *theCreatorPtr = 0;
1573        }
1574        
1575        return;
1576        
1577} /* DRGetTypeCreatorAndFlags */
1578
1579
1580/*
1581 * Vnode pointer to File handle
1582 */
1583/* ARGSUSED */
1584int
1585cd9660_vptofh(struct vnode *vp, int *fhlenp, unsigned char *fhp, __unused vfs_context_t context)
1586{
1587        register struct iso_node *ip = VTOI(vp);
1588        register struct ifid *ifhp;
1589
1590        if (*fhlenp < (int)sizeof(struct ifid))
1591                return (EOVERFLOW);
1592        
1593        ifhp = (struct ifid *)fhp;
1594        
1595        ifhp->ifid_ino = ip->i_number;
1596        ifhp->ifid_start = ip->iso_start;
1597        *fhlenp = sizeof(struct ifid);
1598        
1599#ifdef  ISOFS_DBG
1600        printf("vptofh: ino %d, start %ld\n",
1601               ifhp->ifid_ino,ifhp->ifid_start);
1602#endif
1603        return (0);
1604}
1605
1606/*
1607 * Fast-FileSystem only?
1608 */
1609int
1610cd9660_sysctl(__unused int *name, __unused u_int namelen, __unused user_addr_t oldp,
1611              __unused size_t *oldlenp, __unused user_addr_t newp,
1612              __unused size_t newlen, __unused vfs_context_t context)
1613{
1614     return (ENOTSUP);
1615}
1616
1617
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.