]> git.saurik.com Git - apple/xnu.git/blame - bsd/isofs/cd9660/cd9660_vfsops.c
xnu-792.24.17.tar.gz
[apple/xnu.git] / bsd / isofs / cd9660 / cd9660_vfsops.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
6601e61a 4 * @APPLE_LICENSE_HEADER_START@
1c79356b 5 *
6601e61a
A
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.
8f6c56a5 11 *
6601e61a
A
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
8f6c56a5
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
6601e61a
A
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.
8f6c56a5 19 *
6601e61a 20 * @APPLE_LICENSE_HEADER_END@
1c79356b
A
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>
91447636 66#include <sys/vnode_internal.h>
1c79356b
A
67#include <sys/mount.h>
68#include <sys/namei.h>
69#include <sys/proc.h>
91447636 70#include <sys/kauth.h>
1c79356b
A
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>
55e303ae 76#include <sys/disk.h>
1c79356b
A
77#include <sys/errno.h>
78#include <sys/malloc.h>
79#include <sys/stat.h>
80#include <sys/ubc.h>
0b4e3aa0 81#include <sys/utfconv.h>
6601e61a 82#include <architecture/byte_order.h>
1c79356b
A
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
55e303ae
A
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
1c79356b
A
121u_char isonullname[] = "\0";
122
1c79356b
A
123struct vfsops cd9660_vfsops = {
124 cd9660_mount,
125 cd9660_start,
126 cd9660_unmount,
127 cd9660_root,
91447636
A
128 NULL, /* quotactl */
129 cd9660_vfs_getattr,
1c79356b
A
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
91447636
A
145static int iso_mountfs(struct vnode *devvp, struct mount *mp, struct user_iso_args *argp,
146 vfs_context_t context);
1c79356b
A
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
1c79356b 155int
91447636 156cd9660_mountroot(mount_t mp, vnode_t rvp, vfs_context_t context)
1c79356b 157{
91447636
A
158 int error;
159 struct user_iso_args args;
1c79356b 160
1c79356b
A
161 args.flags = ISOFSMNT_ROOT;
162 args.ssector = 0;
55e303ae 163 args.toc_length = 0;
91447636 164 args.toc = USER_ADDR_NULL;
55e303ae 165
91447636 166 if ((error = iso_mountfs(rvp, mp, &args, context)))
1c79356b 167 return (error);
91447636
A
168
169 (void)cd9660_statfs(mp, vfs_statfs(mp), context);
170
1c79356b
A
171 return (0);
172}
173
174/*
175 * VFS Operations.
176 *
177 * mount system call
178 */
179int
91447636 180cd9660_mount(mount_t mp, vnode_t devvp, user_addr_t data, vfs_context_t context)
1c79356b 181{
91447636 182 struct user_iso_args args;
1c79356b
A
183 int error;
184 struct iso_mnt *imp = NULL;
91447636
A
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)
1c79356b
A
198 return (error);
199
91447636 200 if (vfs_isrdwr(mp))
1c79356b
A
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 */
91447636 207 if (vfs_isupdate(mp)) {
1c79356b 208 imp = VFSTOISOFS(mp);
91447636
A
209 if (devvp == 0)
210 return (0);
1c79356b 211 }
91447636
A
212 if ( !vfs_isupdate(mp))
213 error = iso_mountfs(devvp, mp, &args, context);
1c79356b
A
214 else {
215 if (devvp != imp->im_devvp)
216 error = EINVAL; /* needs translation */
1c79356b
A
217 }
218 if (error) {
1c79356b
A
219 return (error);
220 }
221
55e303ae 222 /* Indicate that we don't support volfs */
91447636 223 vfs_clearflags(mp, MNT_DOVOLFS);
1c79356b 224
1c79356b
A
225 return (0);
226}
227
55e303ae
A
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 *
91447636 241cd9660_phys_device(mount_t mp, vfs_context_t context)
55e303ae
A
242{
243 int err;
91447636 244 char whole_path[64]; // path to "whole" device
55e303ae
A
245 char *s, *saved;
246 struct nameidata nd;
247 struct vnode *result;
91447636 248 struct vfsstatfs * sfs;
55e303ae 249
91447636 250 sfs = vfs_statfs(mp);
55e303ae
A
251 result = NULL;
252
91447636
A
253 if (strlen(sfs->f_mntfromname) >= sizeof(whole_path))
254 return (NULL);
255
55e303ae 256 /* Make a copy of the mount from name, then remove trailing "s...". */
91447636 257 strncpy(whole_path, sfs->f_mntfromname, sizeof(whole_path)-1);
55e303ae
A
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. */
91447636 269 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, CAST_USER_ADDR_T(whole_path), context);
55e303ae
A
270 err = namei(&nd);
271 if (err) {
272 printf("isofs: Cannot find physical device: %s\n", whole_path);
273 goto done;
274 }
91447636
A
275 nameidone(&nd);
276
55e303ae 277 /* Open the "whole" device. */
91447636 278 err = VNOP_OPEN(nd.ni_vp, FREAD, context);
55e303ae 279 if (err) {
91447636 280 vnode_put(nd.ni_vp);
55e303ae
A
281 printf("isofs: Cannot open physical device: %s\n", whole_path);
282 goto done;
283 }
55e303ae 284 result = nd.ni_vp;
55e303ae 285done:
55e303ae
A
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;
91447636 300 struct vnode *rvp = NULL;
55e303ae
A
301 struct vnode *videovp = NULL;
302 struct componentname cn;
91447636 303 struct vfs_context context;
55e303ae
A
304 char dirname[] = "MPEGAV";
305
306 result = 0; /* Assume not a video CD */
307
91447636 308 err = cd9660_root(isomp->im_mountp, &rvp, NULL);
55e303ae
A
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
91447636
A
314 context.vc_proc = current_proc();
315 context.vc_ucred = kauth_cred_get();
316
55e303ae 317 cn.cn_nameiop = LOOKUP;
91447636
A
318 cn.cn_flags = ISLASTCN;
319 cn.cn_context = &context;
55e303ae
A
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
91447636 325 err = VNOP_LOOKUP(rvp, &videovp, &cn, &context);
55e303ae
A
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;
55e303ae 332
91447636
A
333 vnode_put(videovp);
334 }
335 vnode_put(rvp);
55e303ae
A
336
337 return result;
338}
339
1c79356b
A
340/*
341 * Common code for mount and mountroot
342 */
343static int
91447636 344iso_mountfs(devvp, mp, argp, context)
1c79356b
A
345 register struct vnode *devvp;
346 struct mount *mp;
91447636
A
347 struct user_iso_args *argp;
348 vfs_context_t context;
1c79356b 349{
91447636 350 struct proc *p;
1c79356b
A
351 register struct iso_mnt *isomp = (struct iso_mnt *)0;
352 struct buf *bp = NULL;
353 struct buf *pribp = NULL, *supbp = NULL;
91447636 354 dev_t dev = vnode_specrdev(devvp);
1c79356b
A
355 int error = EINVAL;
356 int breaderr = 0;
1c79356b
A
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
91447636 368 if (vfs_isrdwr(mp))
1c79356b
A
369 return (EROFS);
370
1c79356b
A
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 */
91447636
A
378 if ((error = VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
379 (caddr_t)&iso_bsize, FWRITE, context)))
1c79356b 380 return (error);
91447636 381
1c79356b
A
382 joliet_level = 0;
383 for (iso_blknum = 16 + blkoff; iso_blknum < (100 + blkoff); iso_blknum++) {
91447636 384 if ((error = (int)buf_bread(devvp, (daddr64_t)((unsigned)iso_blknum), iso_bsize, NOCRED, &bp))) {
1c79356b 385 if (bp) {
91447636
A
386 buf_markaged(bp);
387 buf_brelse(bp);
1c79356b
A
388 bp = NULL;
389 }
390 breaderr = error;
91447636 391 printf("iso_mountfs: buf_bread error %d reading block %d\n", error, iso_blknum);
1c79356b
A
392 continue;
393 }
394
91447636 395 vdp = (struct iso_volume_descriptor *)buf_dataptr(bp);
1c79356b
A
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
55e303ae
A
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
1c79356b
A
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) {
91447636
A
448 buf_markaged(bp);
449 buf_brelse(bp);
1c79356b
A
450 bp = NULL;
451 }
452 }
453
454 if (bp) {
91447636
A
455 buf_markaged(bp);
456 buf_brelse(bp);
1c79356b
A
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);
55e303ae 480 isomp->im_sector_size = ISO_DEFAULT_BLOCK_SIZE;
1c79356b
A
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 }
0b4e3aa0
A
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));
1c79356b
A
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,
55e303ae 520 sizeof(pri->CDXASignature) ) == 0 ) {
1c79356b 521 isomp->im_flags2 |= IMF2_IS_CDXA;
55e303ae 522 }
1c79356b
A
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
91447636
A
529 buf_markaged(pribp);
530 buf_brelse(pribp);
1c79356b
A
531 pribp = NULL;
532
91447636
A
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);
1c79356b
A
538
539 isomp->im_mountp = mp;
540 isomp->im_dev = dev;
541 isomp->im_devvp = devvp;
542
55e303ae
A
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;
91447636
A
551 if ((error = VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
552 (caddr_t)&iso_bsize, FWRITE, context)))
55e303ae 553 goto out;
55e303ae 554 }
1c79356b
A
555
556 /* Check the Rock Ridge Extention support */
557 if (!(argp->flags & ISOFSMNT_NORRIP)) {
91447636
A
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)) ) {
1c79356b 561
91447636 562 printf("iso_mountfs: buf_bread error %d reading block %d\n",
1c79356b
A
563 error, isomp->root_extent + isonum_711(rootp->ext_attr_length));
564 argp->flags |= ISOFSMNT_NORRIP;
565 goto skipRRIP;
566 }
91447636 567 rootp = (struct iso_directory_record *)buf_dataptr(bp);
1c79356b
A
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 */
91447636
A
579 buf_markaged(bp);
580 buf_brelse(bp);
1c79356b
A
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) {
0b4e3aa0
A
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 *
55e303ae 611 * This name can have up to 16 UCS-2 chars.
0b4e3aa0
A
612 */
613 convflags = UTF_DECOMPOSED;
614 if (BYTE_ORDER != BIG_ENDIAN)
615 convflags |= UTF_REVERSE_ENDIAN;
55e303ae
A
616 uchp = (u_int16_t *)sup->volume_id;
617 for (i = 0; i < 16 && uchp[i]; ++i);
0b4e3aa0
A
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';
55e303ae 627 bcopy(vol_id, isomp->volume_id, convbytes + 1);
0b4e3aa0
A
628 }
629
1c79356b
A
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);
91447636 635 buf_markaged(supbp);
1c79356b
A
636 isomp->iso_ftype = ISO_FTYPE_JOLIET;
637 }
638
639 if (supbp) {
91447636 640 buf_brelse(supbp);
1c79356b
A
641 supbp = NULL;
642 }
643
55e303ae
A
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. */
91447636 654 isomp->phys_devvp = cd9660_phys_device(mp, context);
55e303ae
A
655 }
656
91447636
A
657 /* Fill the default statfs information */
658 (void) cd9660_statfs(mp, vfs_statfs(mp), context);
659
1c79356b
A
660 return (0);
661out:
662 if (bp)
91447636 663 buf_brelse(bp);
1c79356b 664 if (pribp)
91447636 665 buf_brelse(pribp);
1c79356b 666 if (supbp)
91447636
A
667 buf_brelse(supbp);
668
1c79356b 669 if (isomp) {
55e303ae
A
670 if (isomp->toc)
671 FREE((caddr_t)isomp->toc, M_ISOFSMNT);
1c79356b 672 FREE((caddr_t)isomp, M_ISOFSMNT);
1c79356b 673
91447636
A
674 vfs_setfsprivate(mp, (void *)0);
675 }
1c79356b
A
676 return (error);
677}
678
679/*
680 * Make a filesystem operational.
681 * Nothing to do at the moment.
682 */
683/* ARGSUSED */
684int
91447636
A
685cd9660_start(__unused struct mount *mp, __unused int flags,
686 __unused vfs_context_t context)
1c79356b
A
687{
688 return (0);
689}
690
691/*
692 * unmount system call
693 */
694int
91447636 695cd9660_unmount(struct mount *mp, int mntflags, vfs_context_t context)
1c79356b
A
696{
697 register struct iso_mnt *isomp;
698 int error, flags = 0;
9bccf70c 699 int force = 0;
1c79356b 700
9bccf70c 701 if ( (mntflags & MNT_FORCE) ) {
1c79356b 702 flags |= FORCECLOSE;
9bccf70c
A
703 force = 1;
704 }
1c79356b 705
9bccf70c 706 if ( (error = vflush(mp, NULLVP, flags)) && !force )
1c79356b
A
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
55e303ae 715 if (isomp->phys_devvp) {
91447636 716 error = VNOP_CLOSE(isomp->phys_devvp, FREAD, context);
55e303ae
A
717 if (error && !force)
718 return error;
91447636 719 vnode_put(isomp->phys_devvp);
55e303ae
A
720 }
721
722 if (isomp->toc)
723 FREE((caddr_t)isomp->toc, M_ISOFSMNT);
1c79356b 724 FREE((caddr_t)isomp, M_ISOFSMNT);
91447636 725
9bccf70c 726 return (0);
1c79356b
A
727}
728
729/*
730 * Return root of a filesystem
731 */
732int
91447636 733cd9660_root(struct mount *mp, struct vnode **vpp, __unused vfs_context_t context)
1c79356b
A
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 */
91447636 744 return (cd9660_vget_internal(mp, ino, vpp, NULL, NULL,
1c79356b
A
745 imp->iso_ftype == ISO_FTYPE_RRIP, dp, current_proc()));
746}
747
1c79356b
A
748/*
749 * Get file system statistics.
750 */
91447636 751/* ARGSUSED */
1c79356b 752int
91447636
A
753cd9660_statfs(struct mount *mp, register struct vfsstatfs *sbp,
754 __unused vfs_context_t context)
1c79356b
A
755{
756 register struct iso_mnt *isomp;
757
758 isomp = VFSTOISOFS(mp);
759
91447636 760#if 0
1c79356b
A
761#ifdef COMPAT_09
762 sbp->f_type = 5;
763#else
764 sbp->f_type = 0;
765#endif
91447636
A
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';
1c79356b 775
91447636
A
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;
1c79356b
A
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
91447636
A
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
1c79356b
A
894/* ARGSUSED */
895int
91447636
A
896cd9660_sync(__unused struct mount *mp, __unused int waitfor,
897 __unused vfs_context_t context)
1c79356b
A
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 {
1c79356b
A
914 int ifid_ino;
915 long ifid_start;
916};
917
918/* ARGSUSED */
919int
91447636 920cd9660_fhtovp(mount_t mp, int fhlen, unsigned char *fhp, vnode_t *vpp, vfs_context_t context)
1c79356b
A
921{
922 struct ifid *ifhp = (struct ifid *)fhp;
923 register struct iso_node *ip;
1c79356b
A
924 struct vnode *nvp;
925 int error;
926
91447636
A
927 if (fhlen < (int)sizeof(struct ifid))
928 return (EINVAL);
929
1c79356b
A
930#ifdef ISOFS_DBG
931 printf("fhtovp: ino %d, start %ld\n",
932 ifhp->ifid_ino, ifhp->ifid_start);
933#endif
934
6601e61a 935 if ( (error = VFS_VGET(mp, (ino64_t)ifhp->ifid_ino, &nvp, context)) ) {
1c79356b
A
936 *vpp = NULLVP;
937 return (error);
938 }
939 ip = VTOI(nvp);
940 if (ip->inode.iso_mode == 0) {
91447636 941 vnode_put(nvp);
1c79356b
A
942 *vpp = NULLVP;
943 return (ESTALE);
944 }
945 *vpp = nvp;
1c79356b
A
946 return (0);
947}
948
55e303ae
A
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
1c79356b 1035int
91447636 1036cd9660_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, __unused vfs_context_t context)
1c79356b
A
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
91447636
A
1045 return ( cd9660_vget_internal( mp, (ino_t)ino, vpp, NULL, NULL,
1046 0, (struct iso_directory_record *) 0, current_proc()) );
1c79356b
A
1047}
1048
1049int
91447636
A
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)
1c79356b
A
1053{
1054 register struct iso_mnt *imp;
1055 struct iso_node *ip;
91447636
A
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
1c79356b 1068 /* Check for unmount in progress */
91447636
A
1069 if (mp->mnt_kern_flag & MNTK_UNMOUNT)
1070 return (EPERM);
1071#endif
1c79356b
A
1072
1073 MALLOC_ZONE(ip, struct iso_node *, sizeof(struct iso_node),
91447636
A
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);
1c79356b
A
1085 }
1086 bzero((caddr_t)ip, sizeof(struct iso_node));
91447636 1087
1c79356b
A
1088 ip->i_dev = dev;
1089 ip->i_number = ino;
1090 ip->i_namep = &isonullname[0];
91447636
A
1091 ip->i_mnt = imp;
1092 ip->i_devvp = imp->im_devvp;
1c79356b 1093
91447636 1094 SET(ip->i_flag, ISO_INALLOC);
1c79356b
A
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);
91447636 1107
1c79356b 1108 if (lbn >= imp->volume_space_size) {
1c79356b 1109 printf("fhtovp: lbn exceed volume space %d\n", lbn);
91447636
A
1110 error = ESTALE;
1111 goto errout;
1c79356b 1112 }
1c79356b 1113 off = blkoff(imp, ino);
91447636 1114
1c79356b 1115 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
1c79356b
A
1116 printf("fhtovp: crosses block boundary %d\n",
1117 off + ISO_DIRECTORY_RECORD_SIZE);
91447636
A
1118 error = ESTALE;
1119 goto errout;
1c79356b
A
1120 }
1121
91447636
A
1122 error = (int)buf_bread(imp->im_devvp, (daddr64_t)((unsigned)lbn),
1123 imp->logical_block_size, NOCRED, &bp);
1c79356b 1124 if (error) {
91447636
A
1125 printf("fhtovp: buf_bread error %d\n",error);
1126 goto errout;
1c79356b 1127 }
91447636 1128 isodir = (struct iso_directory_record *)(buf_dataptr(bp) + off);
1c79356b 1129
91447636 1130 if (off + isonum_711(isodir->length) > imp->logical_block_size) {
1c79356b
A
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));
91447636
A
1135 error = ESTALE;
1136 goto errout;
1c79356b
A
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 *)
91447636 1148 ((char *)buf_dataptr(bp) + isonum_711(isodir->length));
1c79356b
A
1149 if ((isonum_711(pdp->flags) & directoryBit)
1150 && (pdp->name[0] == 1))
1151 ip->i_parent = isodirino(pdp, imp);
1152 }
91447636 1153 }
1c79356b 1154 if (relocated) {
91447636
A
1155 daddr64_t lbn;
1156
1157 if (bp) {
1158 buf_brelse(bp);
1159 bp = NULL;
1160 }
1c79356b
A
1161 /*
1162 * On relocated directories we must
1163 * read the `.' entry out of a dir.
1164 */
1165 ip->iso_start = ino >> imp->im_bshift;
91447636
A
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);
1c79356b
A
1182 }
1183
1184 /*
1185 * go get apple extensions to ISO directory record or use
1186 * defaults when there are no apple extensions.
1187 */
55e303ae
A
1188 if ( ((isonum_711( isodir->flags ) & directoryBit) == 0) &&
1189 (imp->iso_ftype != ISO_FTYPE_RRIP) ) {
1c79356b 1190 /* This is an ISO directory record for a file */
55e303ae
A
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;
1c79356b
A
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;
55e303ae
A
1208 /*
1209 * account for AppleDouble header
1210 */
1211 if (ip->i_flag & ISO_ASSOCIATED)
1212 ip->i_size += ADH_SIZE;
1c79356b
A
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,
55e303ae 1233 isonum_711(isodir->flags) & directoryBit, ip->i_flag & ISO_ASSOCIATED);
1c79356b
A
1234 break;
1235
1236 default:
1237 isofntrans (isodir->name, namelen,
1238 utf8namep, &namelen,
55e303ae 1239 imp->iso_ftype == ISO_FTYPE_9660, ip->i_flag & ISO_ASSOCIATED);
1c79356b
A
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 */
1c79356b
A
1251 switch (imp->iso_ftype) {
1252 default: /* ISO_FTYPE_9660 */
1253 {
91447636
A
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
1c79356b 1268 bp2 = NULL;
91447636 1269
1c79356b
A
1270 cd9660_defattr(isodir, ip, bp2);
1271 cd9660_deftstamp(isodir, ip, bp2);
91447636 1272
1c79356b 1273 if (bp2)
91447636 1274 buf_brelse(bp2);
1c79356b
A
1275 break;
1276 }
1277 case ISO_FTYPE_RRIP:
1278 cd9660_rrip_analyze(isodir, ip, imp);
1279 break;
1280 }
55e303ae
A
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.
91447636 1284 * We also must substitute the vnop_read and vnop_pagein functions.
55e303ae
A
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 {
91447636
A
1294 cd9660_xa_init(ip, isodir);
1295
1296 is_video_file = 1;
55e303ae 1297 }
1c79356b 1298 if (ip->iso_extent == imp->root_extent) {
1c79356b
A
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 }
91447636
A
1303 vtype = IFTOVT(ip->inode.iso_mode);
1304#if !FIFO
1305 if (vtype == VFIFO) {
1306 error = ENOTSUP;
1307 goto errout;
1308 }
1c79356b 1309#endif
91447636
A
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;
1c79356b 1316 }
91447636 1317#endif
1c79356b 1318 /*
91447636 1319 * create the associated vnode
1c79356b 1320 */
91447636
A
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;
1c79356b 1344
91447636
A
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);
1c79356b
A
1369 *vpp = vp;
1370
91447636
A
1371 CLR(ip->i_flag, ISO_INALLOC);
1372
1373 if (ISSET(ip->i_flag, ISO_INWALLOC))
1374 wakeup(ip);
1375
1c79356b 1376 return (0);
91447636
A
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);
1c79356b
A
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