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