2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* $NetBSD: cd9660_vfsops.c,v 1.18 1995/03/09 12:05:36 mycroft Exp $ */
29 * The Regents of the University of California. All rights reserved.
31 * This code is derived from software contributed to Berkeley
32 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
33 * Support code is derived from software contributed to Berkeley
34 * by Atsushi Murai (amurai@spec.co.jp).
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * @(#)cd9660_vfsops.c 8.9 (Berkeley) 12/5/94
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/vnode.h>
70 #include <sys/mount.h>
71 #include <sys/namei.h>
73 #include <sys/kernel.h>
74 #include <miscfs/specfs/specdev.h>
77 #include <sys/ioctl.h>
79 #include <sys/errno.h>
80 #include <sys/malloc.h>
83 #include <sys/utfconv.h>
84 #include <architecture/byte_order.h>
86 #include <isofs/cd9660/iso.h>
87 #include <isofs/cd9660/iso_rrip.h>
88 #include <isofs/cd9660/cd9660_node.h>
89 #include <isofs/cd9660/cd9660_mount.h>
92 * Minutes, Seconds, Frames (M:S:F)
105 u_char ctrl_adr
; /* typed to be machine and compiler independent */
108 struct CDMSF address
;
114 u_short length
; /* in native cpu endian */
115 u_char first_session
;
117 struct CDTOC_Desc trackdesc
[1];
120 #define MSF_TO_LBA(msf) \
121 (((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
123 u_char isonullname
[] = "\0";
125 extern int enodev ();
127 struct vfsops cd9660_vfsops
= {
143 * Called by vfs_mountroot when iso is going to be mounted as root.
145 * Name is updated by mount(8) after booting.
147 #define ROOTNAME "root_device"
149 static int iso_mountfs
__P((struct vnode
*devvp
, struct mount
*mp
,
150 struct proc
*p
, struct iso_args
*argp
));
152 static void DRGetTypeCreatorAndFlags(
153 struct iso_mnt
* theMountPointPtr
,
154 struct iso_directory_record
* theDirRecPtr
,
155 u_int32_t
* theTypePtr
,
156 u_int32_t
* theCreatorPtr
,
157 u_int16_t
* theFlagsPtr
);
159 int cd9660_vget_internal(
164 struct iso_directory_record
*isodir
,
170 register struct mount
*mp
;
171 extern struct vnode
*rootvp
;
172 struct proc
*p
= current_proc(); /* XXX */
176 struct iso_args args
;
179 * Get vnodes for swapdev and rootdev.
181 if ( bdevvp(rootdev
, &rootvp
))
182 panic("cd9660_mountroot: can't setup bdevvp's");
184 MALLOC_ZONE(mp
, struct mount
*,
185 sizeof(struct mount
), M_MOUNT
, M_WAITOK
);
186 bzero((char *)mp
, (u_long
)sizeof(struct mount
));
188 /* Initialize the default IO constraints */
189 mp
->mnt_maxreadcnt
= mp
->mnt_maxwritecnt
= MAXPHYS
;
190 mp
->mnt_segreadcnt
= mp
->mnt_segwritecnt
= 32;
192 mp
->mnt_op
= &cd9660_vfsops
;
193 mp
->mnt_flag
= MNT_RDONLY
;
194 LIST_INIT(&mp
->mnt_vnodelist
);
195 args
.flags
= ISOFSMNT_ROOT
;
200 if ((error
= iso_mountfs(rootvp
, mp
, p
, &args
))) {
201 vrele(rootvp
); /* release the reference from bdevvp() */
203 if (mp
->mnt_kern_flag
& MNTK_IO_XINFO
)
204 FREE(mp
->mnt_xinfo_ptr
, M_TEMP
);
205 FREE_ZONE(mp
, sizeof (struct mount
), M_MOUNT
);
208 simple_lock(&mountlist_slock
);
209 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
210 simple_unlock(&mountlist_slock
);
211 mp
->mnt_vnodecovered
= NULLVP
;
212 imp
= VFSTOISOFS(mp
);
213 (void) copystr("/", mp
->mnt_stat
.f_mntonname
, MNAMELEN
- 1,
215 bzero(mp
->mnt_stat
.f_mntonname
+ size
, MNAMELEN
- size
);
216 (void) copystr(ROOTNAME
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1,
218 bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
219 (void)cd9660_statfs(mp
, &mp
->mnt_stat
, p
);
229 cd9660_mount(mp
, path
, data
, ndp
, p
)
230 register struct mount
*mp
;
233 struct nameidata
*ndp
;
237 struct iso_args args
;
240 struct iso_mnt
*imp
= NULL
;
242 if ((error
= copyin(data
, (caddr_t
)&args
, sizeof (struct iso_args
))))
245 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
249 * If updating, check whether changing from read-only to
250 * read/write; if there is no device name, that's all we do.
252 if (mp
->mnt_flag
& MNT_UPDATE
) {
253 imp
= VFSTOISOFS(mp
);
255 return (vfs_export(mp
, &imp
->im_export
, &args
.export
));
258 * Not an update, or updating the name: look up the name
259 * and verify that it refers to a sensible block device.
261 NDINIT(ndp
, LOOKUP
, FOLLOW
, UIO_USERSPACE
, args
.fspec
, p
);
262 if ((error
= namei(ndp
)))
266 if (devvp
->v_type
!= VBLK
) {
270 if (major(devvp
->v_rdev
) >= nblkdev
) {
274 if ((mp
->mnt_flag
& MNT_UPDATE
) == 0)
275 error
= iso_mountfs(devvp
, mp
, p
, &args
);
277 if (devvp
!= imp
->im_devvp
)
278 error
= EINVAL
; /* needs translation */
287 /* Indicate that we don't support volfs */
288 mp
->mnt_flag
&= ~MNT_DOVOLFS
;
290 (void) copyinstr(path
, mp
->mnt_stat
.f_mntonname
, MNAMELEN
- 1, &size
);
291 bzero(mp
->mnt_stat
.f_mntonname
+ size
, MNAMELEN
- size
);
292 (void) copyinstr(args
.fspec
, mp
->mnt_stat
.f_mntfromname
, MNAMELEN
- 1,
294 bzero(mp
->mnt_stat
.f_mntfromname
+ size
, MNAMELEN
- size
);
299 * Find the BSD device for the physical disk corresponding to the
300 * mount point's device. We use this physical device to read whole
301 * (2352 byte) sectors from the CD to get the content for the video
304 * The "path" argument is the path to the block device that the volume
305 * is being mounted on (args.fspec). It should be of the form:
307 * where the last "s0" part is stripped off to determine the physical
308 * device's path. It is assumed to be in user memory.
310 static struct vnode
*
311 cd9660_phys_device(char *path
, struct proc
*p
)
314 char *whole_path
= NULL
; // path to "whole" device
317 struct vnode
*result
;
325 /* Make a copy of the mount from name, then remove trailing "s...". */
326 MALLOC(whole_path
, char *, MNAMELEN
, M_ISOFSMNT
, M_WAITOK
);
327 copyinstr(path
, whole_path
, MNAMELEN
-1, &actual_size
);
330 * I would use strrchr or rindex here, but those are declared __private_extern__,
331 * and can't be used across component boundaries at this time.
333 for (s
=whole_path
, saved
=NULL
; *s
; ++s
)
338 /* Lookup the "whole" device. */
339 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, whole_path
, p
);
342 printf("isofs: Cannot find physical device: %s\n", whole_path
);
346 /* Open the "whole" device. */
347 err
= VOP_OPEN(nd
.ni_vp
, FREAD
, FSCRED
, p
);
350 printf("isofs: Cannot open physical device: %s\n", whole_path
);
357 FREE(whole_path
, M_ISOFSMNT
);
363 * See if the given CD-ROM XA disc appears to be a Video CD
364 * (version < 2.0; so, not SVCD). If so, fill in the extent
365 * information for the MPEGAV directory, set the VCD flag,
369 cd9660_find_video_dir(struct iso_mnt
*isomp
)
372 struct vnode
*rootvp
= NULL
;
373 struct vnode
*videovp
= NULL
;
374 struct componentname cn
;
375 char dirname
[] = "MPEGAV";
377 result
= 0; /* Assume not a video CD */
379 err
= cd9660_root(isomp
->im_mountp
, &rootvp
);
381 printf("cd9660_find_video_dir: cd9660_root failed (%d)\n", err
);
382 return 0; /* couldn't find video dir */
385 cn
.cn_nameiop
= LOOKUP
;
386 cn
.cn_flags
= LOCKPARENT
|ISLASTCN
;
387 cn
.cn_proc
= current_proc();
388 cn
.cn_cred
= cn
.cn_proc
->p_ucred
;
389 cn
.cn_pnbuf
= dirname
;
390 cn
.cn_pnlen
= sizeof(dirname
)-1;
391 cn
.cn_nameptr
= cn
.cn_pnbuf
;
392 cn
.cn_namelen
= cn
.cn_pnlen
;
394 err
= VOP_LOOKUP(rootvp
, &videovp
, &cn
);
396 struct iso_node
*ip
= VTOI(videovp
);
397 result
= 1; /* Looks like video CD */
398 isomp
->video_dir_start
= ip
->iso_start
;
399 isomp
->video_dir_end
= ip
->iso_start
+ (ip
->i_size
>> isomp
->im_bshift
);
400 isomp
->im_flags2
|= IMF2_IS_VCD
;
412 * Common code for mount and mountroot
415 iso_mountfs(devvp
, mp
, p
, argp
)
416 register struct vnode
*devvp
;
419 struct iso_args
*argp
;
421 register struct iso_mnt
*isomp
= (struct iso_mnt
*)0;
422 struct buf
*bp
= NULL
;
423 struct buf
*pribp
= NULL
, *supbp
= NULL
;
424 dev_t dev
= devvp
->v_rdev
;
428 extern struct vnode
*rootvp
;
432 struct iso_volume_descriptor
*vdp
= NULL
;
433 struct iso_primary_descriptor
*pri
= NULL
;
434 struct iso_primary_descriptor
*sup
= NULL
;
435 struct iso_directory_record
*rootp
;
436 int logical_block_size
;
438 int blkoff
= argp
->ssector
;
440 if (!(mp
->mnt_flag
& MNT_RDONLY
))
444 * Disallow multiple mounts of the same device.
445 * Disallow mounting of a device that is currently in use
446 * (except for root, which might share swap device for miniroot).
447 * Flush out any old buffers remaining from a previous use.
449 if ((error
= vfs_mountedon(devvp
)))
451 if (vcount(devvp
) > 1 && devvp
!= rootvp
)
453 if ((error
= vinvalbuf(devvp
, V_SAVE
, p
->p_ucred
, p
, 0, 0)))
456 if ((error
= VOP_OPEN(devvp
, FREAD
, FSCRED
, p
)))
460 /* This is the "logical sector size". The standard says this
461 * should be 2048 or the physical sector size on the device,
462 * whichever is greater. For now, we'll just use a constant.
464 iso_bsize
= ISO_DEFAULT_BLOCK_SIZE
;
466 /* tell IOKit that we're assuming 2K sectors */
467 if ((error
= VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
,
468 (caddr_t
)&iso_bsize
, FWRITE
, p
->p_ucred
, p
)))
470 devvp
->v_specsize
= iso_bsize
;
472 for (iso_blknum
= 16 + blkoff
; iso_blknum
< (100 + blkoff
); iso_blknum
++) {
473 if ((error
= bread(devvp
, iso_blknum
, iso_bsize
, NOCRED
, &bp
))) {
475 bp
->b_flags
|= B_AGE
;
480 printf("iso_mountfs: bread error %d reading block %d\n", error
, iso_blknum
);
484 vdp
= (struct iso_volume_descriptor
*)bp
->b_data
;
485 if (bcmp (vdp
->volume_desc_id
, ISO_STANDARD_ID
, sizeof(vdp
->volume_desc_id
)) != 0) {
487 printf("cd9660_vfsops.c: iso_mountfs: "
488 "Invalid ID in volume desciptor.\n");
490 /* There should be a primary volume descriptor followed by any
491 * secondary volume descriptors, then an end volume descriptor.
492 * Some discs are mastered without an end volume descriptor or
493 * they have the type field set and the volume descriptor ID is
494 * not set. If we at least found a primary volume descriptor,
504 vdtype
= isonum_711 (vdp
->type
);
505 if (vdtype
== ISO_VD_END
)
508 if (vdtype
== ISO_VD_PRIMARY
) {
512 pri
= (struct iso_primary_descriptor
*)vdp
;
514 } else if(vdtype
== ISO_VD_SUPPLEMENTARY
) {
518 sup
= (struct iso_primary_descriptor
*)vdp
;
520 if ((argp
->flags
& ISOFSMNT_NOJOLIET
) == 0) {
522 * some Joliet CDs are "out-of-spec and don't correctly
523 * set the SVD flags. We ignore the flags and rely soely
526 if (bcmp(sup
->escape_seq
, ISO_UCS2_Level_1
, 3) == 0)
528 else if (bcmp(sup
->escape_seq
, ISO_UCS2_Level_2
, 3) == 0)
530 else if (bcmp(sup
->escape_seq
, ISO_UCS2_Level_3
, 3) == 0)
537 bp
->b_flags
|= B_AGE
;
544 bp
->b_flags
|= B_AGE
;
557 logical_block_size
= isonum_723 (pri
->logical_block_size
);
559 if (logical_block_size
< DEV_BSIZE
|| logical_block_size
> MAXBSIZE
560 || (logical_block_size
& (logical_block_size
- 1)) != 0) {
565 rootp
= (struct iso_directory_record
*)pri
->root_directory_record
;
567 MALLOC(isomp
, struct iso_mnt
*, sizeof *isomp
, M_ISOFSMNT
, M_WAITOK
);
568 bzero((caddr_t
)isomp
, sizeof *isomp
);
569 isomp
->im_sector_size
= ISO_DEFAULT_BLOCK_SIZE
;
570 isomp
->logical_block_size
= logical_block_size
;
571 isomp
->volume_space_size
= isonum_733 (pri
->volume_space_size
);
573 * Since an ISO9660 multi-session CD can also access previous
574 * sessions, we have to include them into the space consider-
575 * ations. This doesn't yield a very accurate number since
576 * parts of the old sessions might be inaccessible now, but we
577 * can't do much better. This is also important for the NFS
578 * filehandle validation.
580 isomp
->volume_space_size
+= blkoff
;
581 bcopy (rootp
, isomp
->root
, sizeof isomp
->root
);
582 isomp
->root_extent
= isonum_733 (rootp
->extent
);
583 isomp
->root_size
= isonum_733 (rootp
->size
);
586 * getattrlist wants the volume name, create date and modify date
589 /* Remove any trailing white space */
590 if ( strlen(pri
->volume_id
) ) {
593 myPtr
= pri
->volume_id
+ strlen( pri
->volume_id
) - 1;
594 while ( *myPtr
== ' ' && myPtr
>= pri
->volume_id
) {
600 if (pri
->volume_id
[0] == 0)
601 strcpy(isomp
->volume_id
, ISO_DFLT_VOLUME_ID
);
603 bcopy(pri
->volume_id
, isomp
->volume_id
, sizeof(isomp
->volume_id
));
604 cd9660_tstamp_conv17(pri
->creation_date
, &isomp
->creation_date
);
605 cd9660_tstamp_conv17(pri
->modification_date
, &isomp
->modification_date
);
607 /* See if this is a CD-XA volume */
608 if (bcmp( pri
->CDXASignature
, ISO_XA_ID
,
609 sizeof(pri
->CDXASignature
) ) == 0 ) {
610 isomp
->im_flags2
|= IMF2_IS_CDXA
;
613 isomp
->im_bmask
= logical_block_size
- 1;
614 isomp
->im_bshift
= 0;
615 while ((1 << isomp
->im_bshift
) < isomp
->logical_block_size
)
618 pribp
->b_flags
|= B_AGE
;
622 mp
->mnt_data
= (qaddr_t
)isomp
;
623 mp
->mnt_stat
.f_fsid
.val
[0] = (long)dev
;
624 mp
->mnt_stat
.f_fsid
.val
[1] = mp
->mnt_vfc
->vfc_typenum
;
625 mp
->mnt_maxsymlinklen
= 0;
626 mp
->mnt_flag
|= MNT_LOCAL
;
628 isomp
->im_mountp
= mp
;
630 isomp
->im_devvp
= devvp
;
632 devvp
->v_specflags
|= SI_MOUNTEDON
;
635 * If the logical block size is not 2K then we must
636 * set the block device's physical block size to this
637 * disc's logical block size.
640 if (logical_block_size
!= iso_bsize
) {
641 iso_bsize
= logical_block_size
;
642 if ((error
= VOP_IOCTL(devvp
, DKIOCSETBLOCKSIZE
,
643 (caddr_t
)&iso_bsize
, FWRITE
, p
->p_ucred
, p
)))
645 devvp
->v_specsize
= iso_bsize
;
648 /* Check the Rock Ridge Extention support */
649 if (!(argp
->flags
& ISOFSMNT_NORRIP
)) {
650 if ( (error
= bread(isomp
->im_devvp
,
651 (isomp
->root_extent
+ isonum_711(rootp
->ext_attr_length
)),
652 isomp
->logical_block_size
, NOCRED
, &bp
)) ) {
654 printf("iso_mountfs: bread error %d reading block %d\n",
655 error
, isomp
->root_extent
+ isonum_711(rootp
->ext_attr_length
));
656 argp
->flags
|= ISOFSMNT_NORRIP
;
659 rootp
= (struct iso_directory_record
*)bp
->b_data
;
661 if ((isomp
->rr_skip
= cd9660_rrip_offset(rootp
,isomp
)) < 0) {
662 argp
->flags
|= ISOFSMNT_NORRIP
;
664 argp
->flags
&= ~ISOFSMNT_GENS
;
668 * The contents are valid,
669 * but they will get reread as part of another vnode, so...
671 bp
->b_flags
|= B_AGE
;
677 isomp
->im_flags
= argp
->flags
& (ISOFSMNT_NORRIP
| ISOFSMNT_GENS
|
678 ISOFSMNT_EXTATT
| ISOFSMNT_NOJOLIET
);
680 switch (isomp
->im_flags
&(ISOFSMNT_NORRIP
|ISOFSMNT_GENS
)) {
682 isomp
->iso_ftype
= ISO_FTYPE_DEFAULT
;
684 case ISOFSMNT_GENS
|ISOFSMNT_NORRIP
:
685 isomp
->iso_ftype
= ISO_FTYPE_9660
;
688 isomp
->iso_ftype
= ISO_FTYPE_RRIP
;
692 /* Decide whether to use the Joliet descriptor */
694 if (isomp
->iso_ftype
!= ISO_FTYPE_RRIP
&& joliet_level
!= 0) {
701 * On Joliet CDs use the UCS-2 volume identifier.
703 * This name can have up to 16 UCS-2 chars.
705 convflags
= UTF_DECOMPOSED
;
706 if (BYTE_ORDER
!= BIG_ENDIAN
)
707 convflags
|= UTF_REVERSE_ENDIAN
;
708 uchp
= (u_int16_t
*)sup
->volume_id
;
709 for (i
= 0; i
< 16 && uchp
[i
]; ++i
);
710 if ((utf8_encodestr((u_int16_t
*)sup
->volume_id
, (i
* 2), vol_id
,
711 &convbytes
, sizeof(vol_id
), 0, convflags
) == 0)
712 && convbytes
&& (vol_id
[0] != ' ')) {
715 /* Remove trailing spaces */
716 strp
= vol_id
+ convbytes
- 1;
717 while (strp
> vol_id
&& *strp
== ' ')
719 bcopy(vol_id
, isomp
->volume_id
, convbytes
+ 1);
722 rootp
= (struct iso_directory_record
*)
723 sup
->root_directory_record
;
724 bcopy (rootp
, isomp
->root
, sizeof isomp
->root
);
725 isomp
->root_extent
= isonum_733 (rootp
->extent
);
726 isomp
->root_size
= isonum_733 (rootp
->size
);
727 supbp
->b_flags
|= B_AGE
;
728 isomp
->iso_ftype
= ISO_FTYPE_JOLIET
;
736 /* If there was a TOC in the arguments, copy it in. */
737 if (argp
->flags
& ISOFSMNT_TOC
) {
738 MALLOC(isomp
->toc
, struct CDTOC
*, argp
->toc_length
, M_ISOFSMNT
, M_WAITOK
);
739 if ((error
= copyin(argp
->toc
, isomp
->toc
, argp
->toc_length
)))
743 /* See if this could be a Video CD */
744 if ((isomp
->im_flags2
& IMF2_IS_CDXA
) && cd9660_find_video_dir(isomp
)) {
745 /* Get the 2352-bytes-per-block device. */
746 isomp
->phys_devvp
= cd9660_phys_device(argp
->fspec
, p
);
758 (void)VOP_CLOSE(devvp
, FREAD
, NOCRED
, p
);
761 FREE((caddr_t
)isomp
->toc
, M_ISOFSMNT
);
762 FREE((caddr_t
)isomp
, M_ISOFSMNT
);
763 mp
->mnt_data
= (qaddr_t
)0;
766 /* Clear the mounted on bit in the devvp If it */
767 /* not set, this is a nop and there is no way to */
768 /* get here with it set unless we did it. If you*/
769 /* are making code changes which makes the above */
770 /* assumption not true, change this code. */
772 devvp
->v_specflags
&= ~SI_MOUNTEDON
;
778 * Make a filesystem operational.
779 * Nothing to do at the moment.
783 cd9660_start(mp
, flags
, p
)
792 * unmount system call
795 cd9660_unmount(mp
, mntflags
, p
)
800 register struct iso_mnt
*isomp
;
801 int error
, flags
= 0;
804 if ( (mntflags
& MNT_FORCE
) ) {
809 if ( (error
= vflush(mp
, NULLVP
, flags
)) && !force
)
812 isomp
= VFSTOISOFS(mp
);
815 if (isomp
->iso_ftype
== ISO_FTYPE_RRIP
)
816 iso_dunmap(isomp
->im_dev
);
819 isomp
->im_devvp
->v_specflags
&= ~SI_MOUNTEDON
;
820 error
= VOP_CLOSE(isomp
->im_devvp
, FREAD
, NOCRED
, p
);
821 if (error
&& !force
)
824 vrele(isomp
->im_devvp
);
826 if (isomp
->phys_devvp
) {
827 error
= VOP_CLOSE(isomp
->phys_devvp
, FREAD
, FSCRED
, p
);
830 vrele(isomp
->phys_devvp
);
834 FREE((caddr_t
)isomp
->toc
, M_ISOFSMNT
);
836 FREE((caddr_t
)isomp
, M_ISOFSMNT
);
837 mp
->mnt_data
= (qaddr_t
)0;
838 mp
->mnt_flag
&= ~MNT_LOCAL
;
843 * Return root of a filesystem
850 struct iso_mnt
*imp
= VFSTOISOFS(mp
);
851 struct iso_directory_record
*dp
=
852 (struct iso_directory_record
*)imp
->root
;
853 ino_t ino
= isodirino(dp
, imp
);
856 * With RRIP we must use the `.' entry of the root directory.
857 * Simply tell vget, that it's a relocated directory.
859 return (cd9660_vget_internal(mp
, ino
, vpp
,
860 imp
->iso_ftype
== ISO_FTYPE_RRIP
, dp
, current_proc()));
864 * Do operations associated with quotas, not supported
868 cd9660_quotactl(mp
, cmd
, uid
, arg
, p
)
880 * Get file system statistics.
883 cd9660_statfs(mp
, sbp
, p
)
885 register struct statfs
*sbp
;
888 register struct iso_mnt
*isomp
;
890 isomp
= VFSTOISOFS(mp
);
897 sbp
->f_bsize
= isomp
->logical_block_size
;
898 sbp
->f_iosize
= sbp
->f_bsize
; /* XXX */
899 sbp
->f_blocks
= isomp
->volume_space_size
;
900 sbp
->f_bfree
= 0; /* total free blocks */
901 sbp
->f_bavail
= 0; /* blocks free for non superuser */
902 sbp
->f_files
= 0; /* total files */
903 sbp
->f_ffree
= 0; /* free file nodes */
904 if (sbp
!= &mp
->mnt_stat
) {
905 bcopy(mp
->mnt_stat
.f_mntonname
, sbp
->f_mntonname
, MNAMELEN
);
906 bcopy(mp
->mnt_stat
.f_mntfromname
, sbp
->f_mntfromname
, MNAMELEN
);
909 strncpy( sbp
->f_fstypename
, mp
->mnt_vfc
->vfc_name
, (MFSNAMELEN
- 1) );
910 sbp
->f_fstypename
[(MFSNAMELEN
- 1)] = '\0';
912 /* DO NOT use the first spare for flags; it's been reassigned for another use: */
913 /* sbp->f_spare[0] = isomp->im_flags; */
920 cd9660_sync(mp
, waitfor
, cred
, p
)
931 * File handle to vnode
933 * Have to be really careful about stale file handles:
934 * - check that the inode number is in range
935 * - call iget() to get the locked inode
936 * - check for an unallocated inode (i_mode == 0)
937 * - check that the generation number matches
949 cd9660_fhtovp(mp
, fhp
, nam
, vpp
, exflagsp
, credanonp
)
950 register struct mount
*mp
;
955 struct ucred
**credanonp
;
957 struct ifid
*ifhp
= (struct ifid
*)fhp
;
958 register struct iso_node
*ip
;
959 register struct netcred
*np
;
960 register struct iso_mnt
*imp
= VFSTOISOFS(mp
);
965 printf("fhtovp: ino %d, start %ld\n",
966 ifhp
->ifid_ino
, ifhp
->ifid_start
);
970 * Get the export permission structure for this <mp, client> tuple.
972 np
= vfs_export_lookup(mp
, &imp
->im_export
, nam
);
973 if (nam
&& (np
== NULL
))
976 if ( (error
= VFS_VGET(mp
, &ifhp
->ifid_ino
, &nvp
)) ) {
981 if (ip
->inode
.iso_mode
== 0) {
988 *exflagsp
= np
->netc_exflags
;
989 *credanonp
= &np
->netc_anon
;
995 * Scan the TOC for the track which contains the given sector.
997 * If there is no matching track, or no TOC, then return -1.
1000 cd9660_track_for_sector(struct CDTOC
*toc
, u_int sector
)
1002 int i
, tracks
, result
;
1007 tracks
= toc
->length
/ sizeof(struct CDTOC_Desc
);
1009 result
= -1; /* Sentinel in case we don't find the right track. */
1010 for (i
=0; i
<tracks
; ++i
) {
1011 if (toc
->trackdesc
[i
].point
< 100 && MSF_TO_LBA(toc
->trackdesc
[i
].p
) <= sector
) {
1012 result
= toc
->trackdesc
[i
].point
;
1020 * Determine whether the given node is really a video CD video
1021 * file. Return non-zero if it appears to be a video file.
1024 cd9660_is_video_file(struct iso_node
*ip
, struct iso_mnt
*imp
)
1029 /* Check whether this could really be a Video CD at all */
1030 if (((imp
->im_flags2
& IMF2_IS_VCD
) == 0) ||
1031 imp
->phys_devvp
== NULL
||
1034 return 0; /* Doesn't even look like VCD... */
1037 /* Make sure it is a file */
1038 if ((ip
->inode
.iso_mode
& S_IFMT
) != S_IFREG
)
1039 return 0; /* Not even a file... */
1042 * And in the right directory. This assumes the same inode
1043 * number convention that cd9660_vget_internal uses (that
1044 * part of the inode number is the block containing the
1045 * file's directory entry).
1047 lbn
= lblkno(imp
, ip
->i_number
);
1048 if (lbn
< imp
->video_dir_start
|| lbn
>= imp
->video_dir_end
)
1049 return 0; /* Not in the correct directory */
1052 * If we get here, the file should be a video file, but
1053 * do a couple of extra sanity checks just to be sure.
1054 * First, verify the form of the name
1056 if (strlen(ip
->i_namep
) != 11 || /* Wrong length? */
1057 bcmp(ip
->i_namep
+7, ".DAT", 4) || /* Wrong extension? */
1058 (bcmp(ip
->i_namep
, "AVSEQ", 5) && /* Wrong beginning? */
1059 bcmp(ip
->i_namep
, "MUSIC", 5)))
1061 return 0; /* Invalid name format */
1065 * Verify that AVSEQnn.DAT is in track #(nn+1). This would
1066 * not be appropriate for Super Video CD, which allows
1067 * multiple sessions, so the track numbers might not
1068 * match up like this.
1070 track
= (ip
->i_namep
[5] - '0') * 10 + ip
->i_namep
[6] - '0';
1071 if (track
!= (cd9660_track_for_sector(imp
->toc
, ip
->iso_start
) - 1))
1073 return 0; /* Wrong number in name */
1076 /* It must be a video file if we got here. */
1081 cd9660_vget(mp
, ino
, vpp
)
1088 * It would be nice if we didn't always set the `relocated' flag
1089 * and force the extra read, but I don't want to think about fixing
1093 return ( cd9660_vget_internal( mp
, *(ino_t
*)ino
, vpp
, 0,
1094 (struct iso_directory_record
*) 0,
1099 cd9660_vget_internal(mp
, ino
, vpp
, relocated
, isodir
, p
)
1104 struct iso_directory_record
*isodir
;
1107 register struct iso_mnt
*imp
;
1108 struct iso_node
*ip
;
1110 struct vnode
*vp
, *nvp
;
1114 imp
= VFSTOISOFS(mp
);
1117 /* Check for unmount in progress */
1118 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
1123 if ((*vpp
= cd9660_ihashget(dev
, ino
, p
)) != NULLVP
)
1126 MALLOC_ZONE(ip
, struct iso_node
*, sizeof(struct iso_node
),
1127 M_ISOFSNODE
, M_WAITOK
);
1128 /* Allocate a new vnode/iso_node. */
1129 if ( (error
= getnewvnode(VT_ISOFS
, mp
, cd9660_vnodeop_p
, &vp
)) ) {
1130 FREE_ZONE(ip
,sizeof(struct iso_node
), M_ISOFSNODE
);
1134 bzero((caddr_t
)ip
, sizeof(struct iso_node
));
1135 lockinit(&ip
->i_lock
, PINOD
,"isonode",0,0);
1140 ip
->i_namep
= &isonullname
[0];
1143 * Put it onto its hash chain and lock it so that other requests for
1144 * this inode will block if they arrive while we are sleeping waiting
1145 * for old data structures to be purged or for the contents of the
1146 * disk portion of this inode to be read.
1148 cd9660_ihashins(ip
);
1153 lbn
= lblkno(imp
, ino
);
1154 if (lbn
>= imp
->volume_space_size
) {
1156 printf("fhtovp: lbn exceed volume space %d\n", lbn
);
1160 off
= blkoff(imp
, ino
);
1161 if (off
+ ISO_DIRECTORY_RECORD_SIZE
> imp
->logical_block_size
) {
1163 printf("fhtovp: crosses block boundary %d\n",
1164 off
+ ISO_DIRECTORY_RECORD_SIZE
);
1168 error
= bread(imp
->im_devvp
, lbn
,
1169 imp
->logical_block_size
, NOCRED
, &bp
);
1173 printf("fhtovp: bread error %d\n",error
);
1176 isodir
= (struct iso_directory_record
*)(bp
->b_data
+ off
);
1178 if (off
+ isonum_711(isodir
->length
) >
1179 imp
->logical_block_size
) {
1183 printf("fhtovp: directory crosses block boundary "
1184 "%d[off=%d/len=%d]\n",
1185 off
+isonum_711(isodir
->length
), off
,
1186 isonum_711(isodir
->length
));
1191 * for directories we can get parentID from adjacent
1192 * parent directory record
1194 if ((isonum_711(isodir
->flags
) & directoryBit
)
1195 && (isodir
->name
[0] == 0)) {
1196 struct iso_directory_record
*pdp
;
1198 pdp
= (struct iso_directory_record
*)
1199 ((char *)bp
->b_data
+ isonum_711(isodir
->length
));
1200 if ((isonum_711(pdp
->flags
) & directoryBit
)
1201 && (pdp
->name
[0] == 1))
1202 ip
->i_parent
= isodirino(pdp
, imp
);
1208 ip
->i_devvp
= imp
->im_devvp
;
1213 * On relocated directories we must
1214 * read the `.' entry out of a dir.
1216 ip
->iso_start
= ino
>> imp
->im_bshift
;
1219 if ( (error
= VOP_BLKATOFF(vp
, (off_t
)0, NULL
, &bp
)) ) {
1223 isodir
= (struct iso_directory_record
*)bp
->b_data
;
1227 * go get apple extensions to ISO directory record or use
1228 * defaults when there are no apple extensions.
1230 if ( ((isonum_711( isodir
->flags
) & directoryBit
) == 0) &&
1231 (imp
->iso_ftype
!= ISO_FTYPE_RRIP
) ) {
1232 /* This is an ISO directory record for a file */
1233 DRGetTypeCreatorAndFlags(imp
, isodir
, &ip
->i_FileType
,
1234 &ip
->i_Creator
, &ip
->i_FinderFlags
);
1236 if (isonum_711(isodir
->flags
) & associatedBit
)
1237 ip
->i_flag
|= ISO_ASSOCIATED
;
1241 * Shadow the ISO 9660 invisible state to the FinderInfo
1243 if (isonum_711(isodir
->flags
) & existenceBit
) {
1244 ip
->i_FinderFlags
|= fInvisibleBit
;
1247 ip
->iso_extent
= isonum_733(isodir
->extent
);
1248 ip
->i_size
= isonum_733(isodir
->size
);
1249 ip
->iso_start
= isonum_711(isodir
->ext_attr_length
) + ip
->iso_extent
;
1251 * account for AppleDouble header
1253 if (ip
->i_flag
& ISO_ASSOCIATED
)
1254 ip
->i_size
+= ADH_SIZE
;
1257 * if we have a valid name, fill in i_namep with UTF-8 name
1259 if (isonum_711(isodir
->name_len
) != 0) {
1264 MALLOC(utf8namep
, u_char
*, ISO_RRIP_NAMEMAX
+ 1, M_TEMP
, M_WAITOK
);
1265 namelen
= isonum_711(isodir
->name_len
);
1267 switch (imp
->iso_ftype
) {
1268 case ISO_FTYPE_RRIP
:
1269 cd9660_rrip_getname(isodir
, utf8namep
, &namelen
, &inump
, imp
);
1272 case ISO_FTYPE_JOLIET
:
1273 ucsfntrans((u_int16_t
*)isodir
->name
, namelen
,
1274 utf8namep
, &namelen
,
1275 isonum_711(isodir
->flags
) & directoryBit
, ip
->i_flag
& ISO_ASSOCIATED
);
1279 isofntrans (isodir
->name
, namelen
,
1280 utf8namep
, &namelen
,
1281 imp
->iso_ftype
== ISO_FTYPE_9660
, ip
->i_flag
& ISO_ASSOCIATED
);
1284 utf8namep
[namelen
] = '\0';
1285 MALLOC(ip
->i_namep
, u_char
*, namelen
+ 1, M_TEMP
, M_WAITOK
);
1286 bcopy(utf8namep
, ip
->i_namep
, namelen
+ 1);
1287 FREE(utf8namep
, M_TEMP
);
1291 * Setup time stamp, attribute
1294 switch (imp
->iso_ftype
) {
1295 default: /* ISO_FTYPE_9660 */
1299 if ((imp
->im_flags
& ISOFSMNT_EXTATT
)
1300 && (off
= isonum_711(isodir
->ext_attr_length
)))
1301 VOP_BLKATOFF(vp
, (off_t
)-(off
<< imp
->im_bshift
), NULL
, &bp2
);
1304 cd9660_defattr(isodir
, ip
, bp2
);
1305 cd9660_deftstamp(isodir
, ip
, bp2
);
1310 case ISO_FTYPE_RRIP
:
1311 cd9660_rrip_analyze(isodir
, ip
, imp
);
1316 * See if this is a Video CD file. If so, we must adjust the
1317 * length to account for larger sectors plus the RIFF header.
1318 * We also must substitute the VOP_READ and VOP_PAGEIN functions.
1320 * The cd9660_is_video_file routine assumes that the inode has
1321 * been completely set up; it refers to several fields.
1323 * This must be done before we release bp, because isodir
1324 * points into bp's data.
1326 if (cd9660_is_video_file(ip
, imp
))
1328 cd9660_xa_init(vp
, isodir
);
1335 * Initialize the associated vnode
1338 if (ip
->iso_extent
== imp
->root_extent
) {
1339 vp
->v_flag
|= VROOT
;
1340 ip
->i_parent
= 1; /* root's parent is always 1 by convention */
1341 /* mode type must be S_IFDIR */
1342 ip
->inode
.iso_mode
= (ip
->inode
.iso_mode
& ~S_IFMT
) | S_IFDIR
;
1345 switch (vp
->v_type
= IFTOVT(ip
->inode
.iso_mode
)) {
1348 vp
->v_op
= cd9660_fifoop_p
;
1352 return (EOPNOTSUPP
);
1357 * if device, look at device number table for translation
1360 if (dp
= iso_dmap(dev
, ino
, 0))
1361 ip
->inode
.iso_rdev
= dp
->d_dev
;
1363 vp
->v_op
= cd9660_specop_p
;
1364 if ( (nvp
= checkalias(vp
, ip
->inode
.iso_rdev
, mp
)) ) {
1366 * Discard unneeded vnode, but save its iso_node.
1368 cd9660_ihashrem(ip
);
1369 VOP_UNLOCK(vp
, 0, p
);
1370 nvp
->v_data
= vp
->v_data
;
1372 vp
->v_op
= spec_vnodeop_p
;
1376 * Reinitialize aliased inode.
1380 cd9660_ihashins(ip
);
1391 * XXX need generation number?
1400 /************************************************************************
1402 * Function: DRGetTypeCreatorAndFlags
1404 * Purpose: Set up the fileType, fileCreator and fileFlags
1408 * Side Effects: sets *theTypePtr, *theCreatorPtr, and *theFlagsPtr
1413 * 28 Jul 88 BL¡B Added a new extension type of 6, which allows
1414 * the specification of four of the finder flags.
1415 * We let the creator of the disk just copy over
1416 * the finder flags, but we only look at always
1417 * switch launch, system, bundle, and locked bits.
1418 * 15 Aug 88 BL¡B The Apple extensions to ISO 9660 implemented the
1419 * padding field at the end of a directory record
1421 * 19 Jul 89 BG Rewrote routine to handle the "new" Apple
1422 * Extensions definition, as well as take into
1423 * account the possibility of "other" definitions.
1424 * 02 Nov 89 BG Corrected the 'AA' SystemUseID processing to
1425 * check for SystemUseID == 2 (HFS). Was incorrectly
1426 * checking for SystemUseID == 1 (ProDOS) before.
1427 * 18 Mar 92 CMP Fixed the check for whether len_fi was odd or even.
1428 * Before it would always assume even for an XA record.
1429 * 26 Dec 97 jwc Swiped from MacOS implementation of ISO 9660 CD-ROM
1430 * support and modified to work in MacOSX file system.
1432 *********************************************************************** */
1435 DRGetTypeCreatorAndFlags( struct iso_mnt
* theMountPointPtr
,
1436 struct iso_directory_record
* theDirRecPtr
,
1437 u_int32_t
* theTypePtr
,
1438 u_int32_t
* theCreatorPtr
,
1439 u_int16_t
* theFlagsPtr
)
1443 u_int32_t myCreator
;
1444 AppleExtension
*myAppleExtPtr
;
1445 NewAppleExtension
*myNewAppleExtPtr
;
1446 u_int16_t myFinderFlags
;
1450 myType
= 0x3f3f3f3f;
1451 myCreator
= 0x3f3f3f3f;
1453 *theFlagsPtr
= 0x0000;
1456 * handle the fact that our original apple extensions didn't take
1457 * into account the padding byte on a file name
1460 myPtr
= &theDirRecPtr
->name
[ (isonum_711(theDirRecPtr
->name_len
)) ];
1462 /* if string length is even, bump myPtr for padding byte */
1463 if ( ((isonum_711(theDirRecPtr
->name_len
)) & 0x01) == 0 )
1465 myAppleExtPtr
= (AppleExtension
*) myPtr
;
1468 * checking for whether or not the new 'AA' code is being
1469 * called (and if so, correctly)
1471 if ( (isonum_711(theDirRecPtr
->length
)) <=
1472 ISO_DIRECTORY_RECORD_SIZE
+ (isonum_711(theDirRecPtr
->name_len
)) ) {
1477 foundStuff
= 0; /* now we default to *false* until we find a good one */
1478 myPtr
= (char *) myAppleExtPtr
;
1480 if ( (theMountPointPtr
->im_flags2
& IMF2_IS_CDXA
) != 0 )
1481 myPtr
+= 14;/* add in CD-XA fixed record offset (tnx, Phillips) */
1482 myNewAppleExtPtr
= (NewAppleExtension
*) myPtr
;
1485 * Calculate the "real" end of the directory record information.
1487 * Note: We always read the first 4 bytes of the System-Use data, so
1488 * adjust myPtr down so we don't read off the end of the directory!
1490 myPtr
= ((char *) theDirRecPtr
) + (isonum_711(theDirRecPtr
->length
));
1491 myPtr
-= sizeof(NewAppleExtension
) - 1;
1492 while( (char *) myNewAppleExtPtr
< myPtr
) /* end of directory buffer */
1495 * If we get here, we can assume that ALL further entries in this
1496 * directory record are of the form:
1498 * struct OptionalSystemUse
1500 * byte Signature[2];
1503 * byte fileType[4]; # only if HFS
1504 * byte fileCreator[4]; # only if HFS
1505 * byte finderFlags[2]; # only if HFS
1508 * This means that we can examine the Signature bytes to see
1509 * if they are 'AA' (the NEW Apple extension signature).
1510 * If they are, deal with them. If they aren't,
1511 * the OSULength field will tell us how long this extension
1512 * info is (including the signature and length bytes) and that
1513 * will allow us to walk the OptionalSystemUse records until
1514 * we hit the end of them or run off the end of the
1517 u_char
*myFromPtr
, *myToPtr
;
1520 u_int32_t fourchars
;
1524 if ( (myNewAppleExtPtr
->signature
[0] == 'A') &&
1525 (myNewAppleExtPtr
->signature
[1] == 'A') ) {
1526 if ( isonum_711(myNewAppleExtPtr
->systemUseID
) == 2 ) {
1528 foundStuff
= 1; /* we got one! */
1530 myFromPtr
= &myNewAppleExtPtr
->fileType
[0];
1531 myToPtr
= &myChars
.chars
[0];
1532 *myToPtr
++ = *myFromPtr
++;
1533 *myToPtr
++ = *myFromPtr
++;
1534 *myToPtr
++ = *myFromPtr
++;
1535 *myToPtr
= *myFromPtr
;
1536 myType
= myChars
.fourchars
; /* copy file type to user var */
1538 myFromPtr
= &myNewAppleExtPtr
->fileCreator
[0];
1539 myToPtr
= &myChars
.chars
[0];
1540 *myToPtr
++ = *myFromPtr
++;
1541 *myToPtr
++ = *myFromPtr
++;
1542 *myToPtr
++ = *myFromPtr
++;
1543 *myToPtr
= *myFromPtr
;
1544 myCreator
= myChars
.fourchars
; /* copy creator to user var */
1546 myFromPtr
= &myNewAppleExtPtr
->finderFlags
[0];
1547 myToPtr
= &myChars
.chars
[2]; /* *flags* is a short */
1548 myChars
.fourchars
= 0;
1549 *myToPtr
++ = *myFromPtr
++;
1550 *myToPtr
= *myFromPtr
;
1551 myFinderFlags
= myChars
.fourchars
;
1553 ( fAlwaysBit
| fSystemBit
| fHasBundleBit
| fLockedBit
);
1554 /* return Finder flags to user var */
1555 *theFlagsPtr
= (myFinderFlags
| fInitedBit
);
1557 break; /* exit the loop */
1562 * Check to see if we have a reasonable OSULength value.
1563 * ZERO is not an acceptable value. Nor is any value less than 4.
1566 if ( (isonum_711(myNewAppleExtPtr
->OSULength
)) < 4 )
1567 break; /* not acceptable - get out! */
1569 /* otherwise, step past this SystemUse record */
1570 (char *)myNewAppleExtPtr
+= (isonum_711(myNewAppleExtPtr
->OSULength
));
1572 } /* end of while loop */
1575 if ( foundStuff
!= 0 ) {
1576 *theTypePtr
= myType
;
1577 *theCreatorPtr
= myCreator
;
1585 } /* DRGetTypeCreatorAndFlags */
1589 * Vnode pointer to File handle
1593 cd9660_vptofh(vp
, fhp
)
1597 register struct iso_node
*ip
= VTOI(vp
);
1598 register struct ifid
*ifhp
;
1600 ifhp
= (struct ifid
*)fhp
;
1601 ifhp
->ifid_len
= sizeof(struct ifid
);
1603 ifhp
->ifid_ino
= ip
->i_number
;
1604 ifhp
->ifid_start
= ip
->iso_start
;
1607 printf("vptofh: ino %d, start %ld\n",
1608 ifhp
->ifid_ino
,ifhp
->ifid_start
);
1614 * Fast-FileSystem only?
1617 cd9660_sysctl(name
, namelen
, oldp
, oldlenp
, newp
, newlen
, p
)
1626 return (EOPNOTSUPP
);