]> git.saurik.com Git - apple/xnu.git/blame - bsd/isofs/cd9660/cd9660_vfsops.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / isofs / cd9660 / cd9660_vfsops.c
CommitLineData
1c79356b 1/*
0b4e3aa0 2 * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
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
13 * file.
14 *
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
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.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/* $NetBSD: cd9660_vfsops.c,v 1.18 1995/03/09 12:05:36 mycroft Exp $ */
26
27/*-
28 * Copyright (c) 1994
29 * The Regents of the University of California. All rights reserved.
30 *
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).
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
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.
51 *
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
62 * SUCH DAMAGE.
63 *
64 * @(#)cd9660_vfsops.c 8.9 (Berkeley) 12/5/94
65 */
66
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>
72#include <sys/proc.h>
73#include <sys/kernel.h>
74#include <miscfs/specfs/specdev.h>
75#include <sys/buf.h>
76#include <sys/file.h>
77#include <sys/ioctl.h>
78#include <dev/disk.h>
79#include <sys/errno.h>
80#include <sys/malloc.h>
81#include <sys/stat.h>
82#include <sys/ubc.h>
0b4e3aa0
A
83#include <sys/utfconv.h>
84#include <architecture/byte_order.h>
1c79356b
A
85
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>
90
91u_char isonullname[] = "\0";
92
93extern int enodev ();
94
95struct vfsops cd9660_vfsops = {
96 cd9660_mount,
97 cd9660_start,
98 cd9660_unmount,
99 cd9660_root,
100 cd9660_quotactl,
101 cd9660_statfs,
102 cd9660_sync,
103 cd9660_vget,
104 cd9660_fhtovp,
105 cd9660_vptofh,
106 cd9660_init,
107 cd9660_sysctl
108};
109
110/*
111 * Called by vfs_mountroot when iso is going to be mounted as root.
112 *
113 * Name is updated by mount(8) after booting.
114 */
115#define ROOTNAME "root_device"
116
117static int iso_mountfs __P((struct vnode *devvp, struct mount *mp,
118 struct proc *p, struct iso_args *argp));
119
120static void DRGetTypeCreatorAndFlags(
121 struct iso_mnt * theMountPointPtr,
122 struct iso_directory_record * theDirRecPtr,
123 u_int32_t * theTypePtr,
124 u_int32_t * theCreatorPtr,
125 u_int16_t * theFlagsPtr);
126
127int cd9660_vget_internal(
128 struct mount *mp,
129 ino_t ino,
130 struct vnode **vpp,
131 int relocated,
132 struct iso_directory_record *isodir,
133 struct proc *p);
134
135int
136cd9660_mountroot()
137{
138 register struct mount *mp;
139 extern struct vnode *rootvp;
140 struct proc *p = current_proc(); /* XXX */
141 struct iso_mnt *imp;
142 size_t size;
143 int error;
144 struct iso_args args;
145
146 /*
147 * Get vnodes for swapdev and rootdev.
148 */
149 if ( bdevvp(rootdev, &rootvp))
150 panic("cd9660_mountroot: can't setup bdevvp's");
151
152 MALLOC_ZONE(mp, struct mount *,
153 sizeof(struct mount), M_MOUNT, M_WAITOK);
154 bzero((char *)mp, (u_long)sizeof(struct mount));
0b4e3aa0
A
155
156 /* Initialize the default IO constraints */
157 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
158 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
159
1c79356b
A
160 mp->mnt_op = &cd9660_vfsops;
161 mp->mnt_flag = MNT_RDONLY;
162 LIST_INIT(&mp->mnt_vnodelist);
163 args.flags = ISOFSMNT_ROOT;
164 args.ssector = 0;
165 if ((error = iso_mountfs(rootvp, mp, p, &args))) {
9bccf70c 166 vrele(rootvp); /* release the reference from bdevvp() */
1c79356b
A
167 FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
168 return (error);
169 }
170 simple_lock(&mountlist_slock);
171 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
172 simple_unlock(&mountlist_slock);
173 mp->mnt_vnodecovered = NULLVP;
174 imp = VFSTOISOFS(mp);
175 (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1,
176 &size);
177 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
178 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
179 &size);
180 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
181 (void)cd9660_statfs(mp, &mp->mnt_stat, p);
182 return (0);
183}
184
185/*
186 * VFS Operations.
187 *
188 * mount system call
189 */
190int
191cd9660_mount(mp, path, data, ndp, p)
192 register struct mount *mp;
193 char *path;
194 caddr_t data;
195 struct nameidata *ndp;
196 struct proc *p;
197{
198 struct vnode *devvp;
199 struct iso_args args;
200 size_t size;
201 int error;
202 struct iso_mnt *imp = NULL;
203
204 if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args))))
205 return (error);
206
207 if ((mp->mnt_flag & MNT_RDONLY) == 0)
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 */
214 if (mp->mnt_flag & MNT_UPDATE) {
215 imp = VFSTOISOFS(mp);
216 if (args.fspec == 0)
217 return (vfs_export(mp, &imp->im_export, &args.export));
218 }
219 /*
220 * Not an update, or updating the name: look up the name
221 * and verify that it refers to a sensible block device.
222 */
223 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
224 if ((error = namei(ndp)))
225 return (error);
226 devvp = ndp->ni_vp;
227
228 if (devvp->v_type != VBLK) {
229 vrele(devvp);
230 return (ENOTBLK);
231 }
232 if (major(devvp->v_rdev) >= nblkdev) {
233 vrele(devvp);
234 return (ENXIO);
235 }
236 if ((mp->mnt_flag & MNT_UPDATE) == 0)
237 error = iso_mountfs(devvp, mp, p, &args);
238 else {
239 if (devvp != imp->im_devvp)
240 error = EINVAL; /* needs translation */
241 else
242 vrele(devvp);
243 }
244 if (error) {
245 vrele(devvp);
246 return (error);
247 }
248
249 /* Set the mount flag to indicate that we support volfs */
250 mp->mnt_flag |= MNT_DOVOLFS;
251
252 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
253 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
254 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
255 &size);
256 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
257 return (0);
258}
259
260/*
261 * Common code for mount and mountroot
262 */
263static int
264iso_mountfs(devvp, mp, p, argp)
265 register struct vnode *devvp;
266 struct mount *mp;
267 struct proc *p;
268 struct iso_args *argp;
269{
270 register struct iso_mnt *isomp = (struct iso_mnt *)0;
271 struct buf *bp = NULL;
272 struct buf *pribp = NULL, *supbp = NULL;
273 dev_t dev = devvp->v_rdev;
274 int error = EINVAL;
275 int breaderr = 0;
276 int needclose = 0;
277 extern struct vnode *rootvp;
278 u_long iso_bsize;
279 int iso_blknum;
280 int joliet_level;
281 struct iso_volume_descriptor *vdp = NULL;
282 struct iso_primary_descriptor *pri = NULL;
283 struct iso_primary_descriptor *sup = NULL;
284 struct iso_directory_record *rootp;
285 int logical_block_size;
286 u_int8_t vdtype;
287 int blkoff = argp->ssector;
288
289 if (!(mp->mnt_flag & MNT_RDONLY))
290 return (EROFS);
291
292 /*
293 * Disallow multiple mounts of the same device.
294 * Disallow mounting of a device that is currently in use
295 * (except for root, which might share swap device for miniroot).
296 * Flush out any old buffers remaining from a previous use.
297 */
298 if ((error = vfs_mountedon(devvp)))
299 return (error);
300 if (vcount(devvp) > 1 && devvp != rootvp)
301 return (EBUSY);
302 if ((error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)))
303 return (error);
304
305 if ((error = VOP_OPEN(devvp, FREAD, FSCRED, p)))
306 return (error);
307 needclose = 1;
308
309 /* This is the "logical sector size". The standard says this
310 * should be 2048 or the physical sector size on the device,
311 * whichever is greater. For now, we'll just use a constant.
312 */
313 iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
314
315 /* tell IOKit that we're assuming 2K sectors */
316 if ((error = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
317 (caddr_t)&iso_bsize, FWRITE, p->p_ucred, p)))
318 return (error);
319 devvp->v_specsize = iso_bsize;
320 joliet_level = 0;
321 for (iso_blknum = 16 + blkoff; iso_blknum < (100 + blkoff); iso_blknum++) {
322 if ((error = bread(devvp, iso_blknum, iso_bsize, NOCRED, &bp))) {
323 if (bp) {
324 bp->b_flags |= B_AGE;
325 brelse(bp);
326 bp = NULL;
327 }
328 breaderr = error;
329 printf("iso_mountfs: bread error %d reading block %d\n", error, iso_blknum);
330 continue;
331 }
332
333 vdp = (struct iso_volume_descriptor *)bp->b_data;
334 if (bcmp (vdp->volume_desc_id, ISO_STANDARD_ID, sizeof(vdp->volume_desc_id)) != 0) {
335#ifdef DEBUG
336 printf("cd9660_vfsops.c: iso_mountfs: "
337 "Invalid ID in volume desciptor.\n");
338#endif
339 error = EINVAL;
340 goto out;
341 }
342
343 vdtype = isonum_711 (vdp->type);
344 if (vdtype == ISO_VD_END)
345 break;
346
347 if (vdtype == ISO_VD_PRIMARY) {
348 if (pribp == NULL) {
349 pribp = bp;
350 bp = NULL;
351 pri = (struct iso_primary_descriptor *)vdp;
352 }
353 } else if(vdtype == ISO_VD_SUPPLEMENTARY) {
354 if (supbp == NULL) {
355 supbp = bp;
356 bp = NULL;
357 sup = (struct iso_primary_descriptor *)vdp;
358
359 if ((argp->flags & ISOFSMNT_NOJOLIET) == 0) {
360 /*
361 * some Joliet CDs are "out-of-spec and don't correctly
362 * set the SVD flags. We ignore the flags and rely soely
363 * on the escape_seq
364 */
365 if (bcmp(sup->escape_seq, ISO_UCS2_Level_1, 3) == 0)
366 joliet_level = 1;
367 else if (bcmp(sup->escape_seq, ISO_UCS2_Level_2, 3) == 0)
368 joliet_level = 2;
369 else if (bcmp(sup->escape_seq, ISO_UCS2_Level_3, 3) == 0)
370 joliet_level = 3;
371 }
372 }
373 }
374
375 if (bp) {
376 bp->b_flags |= B_AGE;
377 brelse(bp);
378 bp = NULL;
379 }
380 }
381
382 if (bp) {
383 bp->b_flags |= B_AGE;
384 brelse(bp);
385 bp = NULL;
386 }
387
388 if (pri == NULL) {
389 if (breaderr)
390 error = breaderr;
391 else
392 error = EINVAL;
393 goto out;
394 }
395
396 logical_block_size = isonum_723 (pri->logical_block_size);
397
398 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
399 || (logical_block_size & (logical_block_size - 1)) != 0) {
400 error = EINVAL;
401 goto out;
402 }
403
404 rootp = (struct iso_directory_record *)pri->root_directory_record;
405
406 MALLOC(isomp, struct iso_mnt *, sizeof *isomp, M_ISOFSMNT, M_WAITOK);
407 bzero((caddr_t)isomp, sizeof *isomp);
408 isomp->logical_block_size = logical_block_size;
409 isomp->volume_space_size = isonum_733 (pri->volume_space_size);
410 /*
411 * Since an ISO9660 multi-session CD can also access previous
412 * sessions, we have to include them into the space consider-
413 * ations. This doesn't yield a very accurate number since
414 * parts of the old sessions might be inaccessible now, but we
415 * can't do much better. This is also important for the NFS
416 * filehandle validation.
417 */
418 isomp->volume_space_size += blkoff;
419 bcopy (rootp, isomp->root, sizeof isomp->root);
420 isomp->root_extent = isonum_733 (rootp->extent);
421 isomp->root_size = isonum_733 (rootp->size);
422
423 /*
424 * getattrlist wants the volume name, create date and modify date
425 */
426
427 /* Remove any trailing white space */
428 if ( strlen(pri->volume_id) ) {
429 char *myPtr;
430
431 myPtr = pri->volume_id + strlen( pri->volume_id ) - 1;
432 while ( *myPtr == ' ' && myPtr >= pri->volume_id ) {
433 *myPtr = 0x00;
434 myPtr--;
435 }
436 }
0b4e3aa0
A
437
438 if (pri->volume_id[0] == 0)
439 strcpy(isomp->volume_id, ISO_DFLT_VOLUME_ID);
440 else
441 bcopy(pri->volume_id, isomp->volume_id, sizeof(isomp->volume_id));
1c79356b
A
442 cd9660_tstamp_conv17(pri->creation_date, &isomp->creation_date);
443 cd9660_tstamp_conv17(pri->modification_date, &isomp->modification_date);
444
445 /* See if this is a CD-XA volume */
446 if (bcmp( pri->CDXASignature, ISO_XA_ID,
447 sizeof(pri->CDXASignature) ) == 0 )
448 isomp->im_flags2 |= IMF2_IS_CDXA;
449
450 isomp->im_bmask = logical_block_size - 1;
451 isomp->im_bshift = 0;
452 while ((1 << isomp->im_bshift) < isomp->logical_block_size)
453 isomp->im_bshift++;
454
455 pribp->b_flags |= B_AGE;
456 brelse(pribp);
457 pribp = NULL;
458
459 mp->mnt_data = (qaddr_t)isomp;
460 mp->mnt_stat.f_fsid.val[0] = (long)dev;
461 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
462 mp->mnt_maxsymlinklen = 0;
463 mp->mnt_flag |= MNT_LOCAL;
464
465 isomp->im_mountp = mp;
466 isomp->im_dev = dev;
467 isomp->im_devvp = devvp;
468
469 devvp->v_specflags |= SI_MOUNTEDON;
470
471 /* Check the Rock Ridge Extention support */
472 if (!(argp->flags & ISOFSMNT_NORRIP)) {
473 if ( (error = bread(isomp->im_devvp,
474 (isomp->root_extent + isonum_711(rootp->ext_attr_length)),
475 isomp->logical_block_size, NOCRED, &bp)) ) {
476
477 printf("iso_mountfs: bread error %d reading block %d\n",
478 error, isomp->root_extent + isonum_711(rootp->ext_attr_length));
479 argp->flags |= ISOFSMNT_NORRIP;
480 goto skipRRIP;
481 }
482 rootp = (struct iso_directory_record *)bp->b_data;
483
484 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
485 argp->flags |= ISOFSMNT_NORRIP;
486 } else {
487 argp->flags &= ~ISOFSMNT_GENS;
488 }
489
490 /*
491 * The contents are valid,
492 * but they will get reread as part of another vnode, so...
493 */
494 bp->b_flags |= B_AGE;
495 brelse(bp);
496 bp = NULL;
497 }
498skipRRIP:
499
500 isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
501 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET);
502
503 switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
504 default:
505 isomp->iso_ftype = ISO_FTYPE_DEFAULT;
506 break;
507 case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
508 isomp->iso_ftype = ISO_FTYPE_9660;
509 break;
510 case 0:
511 isomp->iso_ftype = ISO_FTYPE_RRIP;
512 break;
513 }
514
515 /* Decide whether to use the Joliet descriptor */
516
517 if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level != 0) {
0b4e3aa0
A
518 char vol_id[32];
519 int i, convflags;
520 size_t convbytes;
521 u_int16_t *uchp;
522
523 /*
524 * On Joliet CDs use the UCS-2 volume identifier.
525 *
526 * This name can have up to 15 UCS-2 chars and is
527 * terminated with 0x0000 or padded with 0x0020.
528 */
529 convflags = UTF_DECOMPOSED;
530 if (BYTE_ORDER != BIG_ENDIAN)
531 convflags |= UTF_REVERSE_ENDIAN;
532 for (i = 0, uchp = (u_int16_t *)sup->volume_id; i < 15 && uchp[i]; ++i);
533 if ((utf8_encodestr((u_int16_t *)sup->volume_id, (i * 2), vol_id,
534 &convbytes, sizeof(vol_id), 0, convflags) == 0)
535 && convbytes && (vol_id[0] != ' ')) {
536 char * strp;
537
538 /* Remove trailing spaces */
539 strp = vol_id + convbytes - 1;
540 while (strp > vol_id && *strp == ' ')
541 *strp-- = '\0';
542 bcopy(vol_id, isomp->volume_id, convbytes);
543 }
544
1c79356b
A
545 rootp = (struct iso_directory_record *)
546 sup->root_directory_record;
547 bcopy (rootp, isomp->root, sizeof isomp->root);
548 isomp->root_extent = isonum_733 (rootp->extent);
549 isomp->root_size = isonum_733 (rootp->size);
550 supbp->b_flags |= B_AGE;
551 isomp->iso_ftype = ISO_FTYPE_JOLIET;
552 }
553
554 if (supbp) {
555 brelse(supbp);
556 supbp = NULL;
557 }
558
559 return (0);
560out:
561 if (bp)
562 brelse(bp);
563 if (pribp)
564 brelse(pribp);
565 if (supbp)
566 brelse(supbp);
567 if (needclose)
568 (void)VOP_CLOSE(devvp, FREAD, NOCRED, p);
569 if (isomp) {
570 FREE((caddr_t)isomp, M_ISOFSMNT);
571 mp->mnt_data = (qaddr_t)0;
572 }
573
574 /* Clear the mounted on bit in the devvp If it */
575 /* not set, this is a nop and there is no way to */
576 /* get here with it set unless we did it. If you*/
577 /* are making code changes which makes the above */
578 /* assumption not true, change this code. */
579
580 devvp->v_specflags &= ~SI_MOUNTEDON;
581
582 return (error);
583}
584
585/*
586 * Make a filesystem operational.
587 * Nothing to do at the moment.
588 */
589/* ARGSUSED */
590int
591cd9660_start(mp, flags, p)
592 struct mount *mp;
593 int flags;
594 struct proc *p;
595{
596 return (0);
597}
598
599/*
600 * unmount system call
601 */
602int
603cd9660_unmount(mp, mntflags, p)
604 struct mount *mp;
605 int mntflags;
606 struct proc *p;
607{
608 register struct iso_mnt *isomp;
609 int error, flags = 0;
9bccf70c 610 int force = 0;
1c79356b 611
9bccf70c 612 if ( (mntflags & MNT_FORCE) ) {
1c79356b 613 flags |= FORCECLOSE;
9bccf70c
A
614 force = 1;
615 }
1c79356b 616
9bccf70c 617 if ( (error = vflush(mp, NULLVP, flags)) && !force )
1c79356b
A
618 return (error);
619
620 isomp = VFSTOISOFS(mp);
621
622#ifdef ISODEVMAP
623 if (isomp->iso_ftype == ISO_FTYPE_RRIP)
624 iso_dunmap(isomp->im_dev);
625#endif
626
627 isomp->im_devvp->v_specflags &= ~SI_MOUNTEDON;
628 error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p);
9bccf70c
A
629 if (error && !force )
630 return(error);
631
1c79356b
A
632 vrele(isomp->im_devvp);
633 FREE((caddr_t)isomp, M_ISOFSMNT);
634 mp->mnt_data = (qaddr_t)0;
635 mp->mnt_flag &= ~MNT_LOCAL;
9bccf70c 636 return (0);
1c79356b
A
637}
638
639/*
640 * Return root of a filesystem
641 */
642int
643cd9660_root(mp, vpp)
644 struct mount *mp;
645 struct vnode **vpp;
646{
647 struct iso_mnt *imp = VFSTOISOFS(mp);
648 struct iso_directory_record *dp =
649 (struct iso_directory_record *)imp->root;
650 ino_t ino = isodirino(dp, imp);
651
652 /*
653 * With RRIP we must use the `.' entry of the root directory.
654 * Simply tell vget, that it's a relocated directory.
655 */
656 return (cd9660_vget_internal(mp, ino, vpp,
657 imp->iso_ftype == ISO_FTYPE_RRIP, dp, current_proc()));
658}
659
660/*
661 * Do operations associated with quotas, not supported
662 */
663/* ARGSUSED */
664int
665cd9660_quotactl(mp, cmd, uid, arg, p)
666 struct mount *mp;
667 int cmd;
668 uid_t uid;
669 caddr_t arg;
670 struct proc *p;
671{
672
673 return (EOPNOTSUPP);
674}
675
676/*
677 * Get file system statistics.
678 */
679int
680cd9660_statfs(mp, sbp, p)
681 struct mount *mp;
682 register struct statfs *sbp;
683 struct proc *p;
684{
685 register struct iso_mnt *isomp;
686
687 isomp = VFSTOISOFS(mp);
688
689#ifdef COMPAT_09
690 sbp->f_type = 5;
691#else
692 sbp->f_type = 0;
693#endif
694 sbp->f_bsize = isomp->logical_block_size;
695 sbp->f_iosize = sbp->f_bsize; /* XXX */
696 sbp->f_blocks = isomp->volume_space_size;
697 sbp->f_bfree = 0; /* total free blocks */
698 sbp->f_bavail = 0; /* blocks free for non superuser */
699 sbp->f_files = 0; /* total files */
700 sbp->f_ffree = 0; /* free file nodes */
701 if (sbp != &mp->mnt_stat) {
702 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
703 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
704 }
705
706 strncpy( sbp->f_fstypename, mp->mnt_vfc->vfc_name, (MFSNAMELEN - 1) );
707 sbp->f_fstypename[(MFSNAMELEN - 1)] = '\0';
708
709 /* DO NOT use the first spare for flags; it's been reassigned for another use: */
710 /* sbp->f_spare[0] = isomp->im_flags; */
711
712 return (0);
713}
714
715/* ARGSUSED */
716int
717cd9660_sync(mp, waitfor, cred, p)
718 struct mount *mp;
719 int waitfor;
720 struct ucred *cred;
721 struct proc *p;
722{
723
724 return (0);
725}
726
727/*
728 * File handle to vnode
729 *
730 * Have to be really careful about stale file handles:
731 * - check that the inode number is in range
732 * - call iget() to get the locked inode
733 * - check for an unallocated inode (i_mode == 0)
734 * - check that the generation number matches
735 */
736
737struct ifid {
738 ushort ifid_len;
739 ushort ifid_pad;
740 int ifid_ino;
741 long ifid_start;
742};
743
744/* ARGSUSED */
745int
746cd9660_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
747 register struct mount *mp;
748 struct fid *fhp;
749 struct mbuf *nam;
750 struct vnode **vpp;
751 int *exflagsp;
752 struct ucred **credanonp;
753{
754 struct ifid *ifhp = (struct ifid *)fhp;
755 register struct iso_node *ip;
756 register struct netcred *np;
757 register struct iso_mnt *imp = VFSTOISOFS(mp);
758 struct vnode *nvp;
759 int error;
760
761#ifdef ISOFS_DBG
762 printf("fhtovp: ino %d, start %ld\n",
763 ifhp->ifid_ino, ifhp->ifid_start);
764#endif
765
766 /*
767 * Get the export permission structure for this <mp, client> tuple.
768 */
769 np = vfs_export_lookup(mp, &imp->im_export, nam);
770 if (np == NULL)
771 return (EACCES);
772
773 if ( (error = VFS_VGET(mp, &ifhp->ifid_ino, &nvp)) ) {
774 *vpp = NULLVP;
775 return (error);
776 }
777 ip = VTOI(nvp);
778 if (ip->inode.iso_mode == 0) {
779 vput(nvp);
780 *vpp = NULLVP;
781 return (ESTALE);
782 }
783 *vpp = nvp;
784 *exflagsp = np->netc_exflags;
785 *credanonp = &np->netc_anon;
786 return (0);
787}
788
789int
790cd9660_vget(mp, ino, vpp)
791 struct mount *mp;
792 void *ino;
793 struct vnode **vpp;
794{
795 /*
796 * XXXX
797 * It would be nice if we didn't always set the `relocated' flag
798 * and force the extra read, but I don't want to think about fixing
799 * that right now.
800 */
801
802 return ( cd9660_vget_internal( mp, *(ino_t*)ino, vpp, 0,
803 (struct iso_directory_record *) 0,
804 current_proc()) );
805}
806
807int
808cd9660_vget_internal(mp, ino, vpp, relocated, isodir, p)
809 struct mount *mp;
810 ino_t ino;
811 struct vnode **vpp;
812 int relocated;
813 struct iso_directory_record *isodir;
814 struct proc *p;
815{
816 register struct iso_mnt *imp;
817 struct iso_node *ip;
818 struct buf *bp;
819 struct vnode *vp, *nvp;
820 dev_t dev;
821 int error;
822
823 imp = VFSTOISOFS(mp);
824 dev = imp->im_dev;
825
826 /* Check for unmount in progress */
827 if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
828 *vpp = NULLVP;
829 return (EPERM);
830 }
831
832 if ((*vpp = cd9660_ihashget(dev, ino, p)) != NULLVP)
833 return (0);
834
835 MALLOC_ZONE(ip, struct iso_node *, sizeof(struct iso_node),
836 M_ISOFSNODE, M_WAITOK);
837 /* Allocate a new vnode/iso_node. */
838 if ( (error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) ) {
839 FREE_ZONE(ip,sizeof(struct iso_node), M_ISOFSNODE);
840 *vpp = NULLVP;
841 return (error);
842 }
843 bzero((caddr_t)ip, sizeof(struct iso_node));
844 lockinit(&ip->i_lock, PINOD,"isonode",0,0);
845 vp->v_data = ip;
846 ip->i_vnode = vp;
847 ip->i_dev = dev;
848 ip->i_number = ino;
849 ip->i_namep = &isonullname[0];
850
851 /*
852 * Put it onto its hash chain and lock it so that other requests for
853 * this inode will block if they arrive while we are sleeping waiting
854 * for old data structures to be purged or for the contents of the
855 * disk portion of this inode to be read.
856 */
857 cd9660_ihashins(ip);
858
859 if (isodir == 0) {
860 int lbn, off;
861
862 lbn = lblkno(imp, ino);
863 if (lbn >= imp->volume_space_size) {
864 vput(vp);
865 printf("fhtovp: lbn exceed volume space %d\n", lbn);
866 return (ESTALE);
867 }
868
869 off = blkoff(imp, ino);
870 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
871 vput(vp);
872 printf("fhtovp: crosses block boundary %d\n",
873 off + ISO_DIRECTORY_RECORD_SIZE);
874 return (ESTALE);
875 }
876
877 error = bread(imp->im_devvp, lbn,
878 imp->logical_block_size, NOCRED, &bp);
879 if (error) {
880 vput(vp);
881 brelse(bp);
882 printf("fhtovp: bread error %d\n",error);
883 return (error);
884 }
885 isodir = (struct iso_directory_record *)(bp->b_data + off);
886
887 if (off + isonum_711(isodir->length) >
888 imp->logical_block_size) {
889 vput(vp);
890 if (bp != 0)
891 brelse(bp);
892 printf("fhtovp: directory crosses block boundary "
893 "%d[off=%d/len=%d]\n",
894 off +isonum_711(isodir->length), off,
895 isonum_711(isodir->length));
896 return (ESTALE);
897 }
898
899 /*
900 * for directories we can get parentID from adjacent
901 * parent directory record
902 */
903 if ((isonum_711(isodir->flags) & directoryBit)
904 && (isodir->name[0] == 0)) {
905 struct iso_directory_record *pdp;
906
907 pdp = (struct iso_directory_record *)
908 ((char *)bp->b_data + isonum_711(isodir->length));
909 if ((isonum_711(pdp->flags) & directoryBit)
910 && (pdp->name[0] == 1))
911 ip->i_parent = isodirino(pdp, imp);
912 }
913 } else
914 bp = 0;
915
916 ip->i_mnt = imp;
917 ip->i_devvp = imp->im_devvp;
918 VREF(ip->i_devvp);
919
920 if (relocated) {
921 /*
922 * On relocated directories we must
923 * read the `.' entry out of a dir.
924 */
925 ip->iso_start = ino >> imp->im_bshift;
926 if (bp != 0)
927 brelse(bp);
928 if ( (error = VOP_BLKATOFF(vp, (off_t)0, NULL, &bp)) ) {
929 vput(vp);
930 return (error);
931 }
932 isodir = (struct iso_directory_record *)bp->b_data;
933 }
934
935 /*
936 * go get apple extensions to ISO directory record or use
937 * defaults when there are no apple extensions.
938 */
939 if ( (isonum_711( isodir->flags ) & directoryBit) == 0 ) {
940 /* This is an ISO directory record for a file */
941 DRGetTypeCreatorAndFlags( imp, isodir, &ip->i_FileType,
942 &ip->i_Creator, &ip->i_FinderFlags );
943 }
944
945 ip->iso_extent = isonum_733(isodir->extent);
946 ip->i_size = isonum_733(isodir->size);
947 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
948
949 /*
950 * if we have a valid name, fill in i_namep with UTF-8 name
951 */
952 if (isonum_711(isodir->name_len) != 0) {
953 u_char *utf8namep;
954 u_short namelen;
955 ino_t inump = 0;
956
957 MALLOC(utf8namep, u_char *, ISO_RRIP_NAMEMAX + 1, M_TEMP, M_WAITOK);
958 namelen = isonum_711(isodir->name_len);
959
960 switch (imp->iso_ftype) {
961 case ISO_FTYPE_RRIP:
962 cd9660_rrip_getname(isodir, utf8namep, &namelen, &inump, imp);
963 break;
964
965 case ISO_FTYPE_JOLIET:
966 ucsfntrans((u_int16_t *)isodir->name, namelen,
967 utf8namep, &namelen,
968 isonum_711(isodir->flags) & directoryBit);
969 break;
970
971 default:
972 isofntrans (isodir->name, namelen,
973 utf8namep, &namelen,
974 imp->iso_ftype == ISO_FTYPE_9660);
975 }
976
977 utf8namep[namelen] = '\0';
978 MALLOC(ip->i_namep, u_char *, namelen + 1, M_TEMP, M_WAITOK);
979 bcopy(utf8namep, ip->i_namep, namelen + 1);
980 FREE(utf8namep, M_TEMP);
981 }
982
983 /*
984 * Setup time stamp, attribute
985 */
986 vp->v_type = VNON;
987 switch (imp->iso_ftype) {
988 default: /* ISO_FTYPE_9660 */
989 {
990 struct buf *bp2;
991 int off;
992 if ((imp->im_flags & ISOFSMNT_EXTATT)
993 && (off = isonum_711(isodir->ext_attr_length)))
994 VOP_BLKATOFF(vp, (off_t)-(off << imp->im_bshift), NULL, &bp2);
995 else
996 bp2 = NULL;
997 cd9660_defattr(isodir, ip, bp2);
998 cd9660_deftstamp(isodir, ip, bp2);
999 if (bp2)
1000 brelse(bp2);
1001 break;
1002 }
1003 case ISO_FTYPE_RRIP:
1004 cd9660_rrip_analyze(isodir, ip, imp);
1005 break;
1006 }
1007
1008 if (bp != 0)
1009 brelse(bp);
1010
1011 /*
1012 * Initialize the associated vnode
1013 */
1014
1015 if (ip->iso_extent == imp->root_extent) {
1016 vp->v_flag |= VROOT;
1017 ip->i_parent = 1; /* root's parent is always 1 by convention */
1018 /* mode type must be S_IFDIR */
1019 ip->inode.iso_mode = (ip->inode.iso_mode & ~S_IFMT) | S_IFDIR;
1020 }
1021
1022 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
1023 case VFIFO:
1024#if FIFO
1025 vp->v_op = cd9660_fifoop_p;
1026 break;
1027#else
1028 vput(vp);
1029 return (EOPNOTSUPP);
1030#endif /* FIFO */
1031 case VCHR:
1032 case VBLK:
1033 /*
1034 * if device, look at device number table for translation
1035 */
1036#ifdef ISODEVMAP
1037 if (dp = iso_dmap(dev, ino, 0))
1038 ip->inode.iso_rdev = dp->d_dev;
1039#endif
1040 vp->v_op = cd9660_specop_p;
1041 if ( (nvp = checkalias(vp, ip->inode.iso_rdev, mp)) ) {
1042 /*
1043 * Discard unneeded vnode, but save its iso_node.
1044 */
1045 cd9660_ihashrem(ip);
1046 VOP_UNLOCK(vp, 0, p);
1047 nvp->v_data = vp->v_data;
1048 vp->v_data = NULL;
1049 vp->v_op = spec_vnodeop_p;
1050 vrele(vp);
1051 vgone(vp);
1052 /*
1053 * Reinitialize aliased inode.
1054 */
1055 vp = nvp;
1056 ip->i_vnode = vp;
1057 cd9660_ihashins(ip);
1058 }
1059 break;
1060 case VREG:
1061 ubc_info_init(vp);
1062 break;
1063 default:
1064 break;
1065 }
1066
1067 /*
1068 * XXX need generation number?
1069 */
1070
1071 *vpp = vp;
1072
1073 return (0);
1074}
1075
1076
1077/************************************************************************
1078 *
1079 * Function: DRGetTypeCreatorAndFlags
1080 *
1081 * Purpose: Set up the fileType, fileCreator and fileFlags
1082 *
1083 * Returns: none
1084 *
1085 * Side Effects: sets *theTypePtr, *theCreatorPtr, and *theFlagsPtr
1086 *
1087 * Description:
1088 *
1089 * Revision History:
1090