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