1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64#include <sys/param.h>
65#include <sys/systm.h>
66#include <sys/vnode_internal.h>
67#include <sys/mount.h>
68#include <sys/namei.h>
69#include <sys/proc.h>
70#include <sys/kauth.h>
71#include <sys/kernel.h>
72#include <miscfs/specfs/specdev.h>
73#include <sys/buf.h>
74#include <sys/file.h>
75#include <sys/ioctl.h>
76#include <sys/disk.h>
77#include <sys/errno.h>
78#include <sys/malloc.h>
79#include <sys/stat.h>
80#include <sys/ubc.h>
81#include <sys/utfconv.h>
82#include <architecture/byte_order.h>
83
84#include <isofs/cd9660/iso.h>
85#include <isofs/cd9660/iso_rrip.h>
86#include <isofs/cd9660/cd9660_node.h>
87#include <isofs/cd9660/cd9660_mount.h>
88
89
90
91
92struct CDMSF {
93 u_char minute;
94 u_char second;
95 u_char frame;
96};
97
98
99
100
101struct CDTOC_Desc {
102 u_char session;
103 u_char ctrl_adr;
104 u_char tno;
105 u_char point;
106 struct CDMSF address;
107 u_char zero;
108 struct CDMSF p;
109};
110
111struct CDTOC {
112 u_short length;
113 u_char first_session;
114 u_char last_session;
115 struct CDTOC_Desc trackdesc[1];
116};
117
118#define MSF_TO_LBA(msf) \
119 (((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
120
121u_char isonullname[] = "\0";
122
123struct vfsops cd9660_vfsops = {
124 cd9660_mount,
125 cd9660_start,
126 cd9660_unmount,
127 cd9660_root,
128 NULL,
129 cd9660_vfs_getattr,
130 cd9660_sync,
131 cd9660_vget,
132 cd9660_fhtovp,
133 cd9660_vptofh,
134 cd9660_init,
135 cd9660_sysctl
136};
137
138
139
140
141
142
143#define ROOTNAME "root_device"
144
145static int iso_mountfs(struct vnode *devvp, struct mount *mp, struct user_iso_args *argp,
146 vfs_context_t context);
147
148static void DRGetTypeCreatorAndFlags(
149 struct iso_mnt * theMountPointPtr,
150 struct iso_directory_record * theDirRecPtr,
151 u_int32_t * theTypePtr,
152 u_int32_t * theCreatorPtr,
153 u_int16_t * theFlagsPtr);
154
155int
156cd9660_mountroot(mount_t mp, vnode_t rvp, vfs_context_t context)
157{
158 int error;
159 struct user_iso_args args;
160
161 args.flags = ISOFSMNT_ROOT;
162 args.ssector = 0;
163 args.toc_length = 0;
164 args.toc = USER_ADDR_NULL;
165
166 if ((error = iso_mountfs(rvp, mp, &args, context)))
167 return (error);
168
169 (void)cd9660_statfs(mp, vfs_statfs(mp), context);
170
171 return (0);
172}
173
174
175
176
177
178
179int
180cd9660_mount(mount_t mp, vnode_t devvp, user_addr_t data, vfs_context_t context)
181{
182 struct user_iso_args args;
183 int error;
184 struct iso_mnt *imp = NULL;
185
186 if (vfs_context_is64bit(context)) {
187 error = copyin(data, (caddr_t)&args, sizeof (args));
188 }
189 else {
190 struct iso_args temp;
191 error = copyin(data, (caddr_t)&temp, sizeof (temp));
192 args.flags = temp.flags;
193 args.ssector = temp.ssector;
194 args.toc_length = temp.toc_length;
195 args.toc = CAST_USER_ADDR_T(temp.toc);
196 }
197 if (error)
198 return (error);
199
200 if (vfs_isrdwr(mp))
201 return (EROFS);
202
203
204
205
206
207 if (vfs_isupdate(mp)) {
208 imp = VFSTOISOFS(mp);
209 if (devvp == 0)
210 return (0);
211 }
212 if ( !vfs_isupdate(mp))
213 error = iso_mountfs(devvp, mp, &args, context);
214 else {
215 if (devvp != imp->im_devvp)
216 error = EINVAL;
217 }
218 if (error) {
219 return (error);
220 }
221
222
223 vfs_clearflags(mp, MNT_DOVOLFS);
224
225 return (0);
226}
227
228
229
230
231
232
233
234
235
236
237
238
239
240static struct vnode *
241cd9660_phys_device(mount_t mp, vfs_context_t context)
242{
243 int err;
244 char whole_path[64];
245 char *s, *saved;
246 struct nameidata nd;
247 struct vnode *result;
248 struct vfsstatfs * sfs;
249
250 sfs = vfs_statfs(mp);
251 result = NULL;
252
253 if (strlen(sfs->f_mntfromname) >= sizeof(whole_path))
254 return (NULL);
255
256
257 strncpy(whole_path, sfs->f_mntfromname, sizeof(whole_path)-1);
258
259
260
261
262
263 for (s=whole_path, saved=NULL; *s; ++s)
264 if (*s == 's')
265 saved = s;
266 *saved = '\0';
267
268
269 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, CAST_USER_ADDR_T(whole_path), context);
270 err = namei(&nd);
271 if (err) {
272 printf("isofs: Cannot find physical device: %s\n", whole_path);
273 goto done;
274 }
275 nameidone(&nd);
276
277
278 err = VNOP_OPEN(nd.ni_vp, FREAD, context);
279 if (err) {
280 vnode_put(nd.ni_vp);
281 printf("isofs: Cannot open physical device: %s\n", whole_path);
282 goto done;
283 }
284 result = nd.ni_vp;
285done:
286 return result;
287}
288
289
290
291
292
293
294
295
296static int
297cd9660_find_video_dir(struct iso_mnt *isomp)
298{
299 int result, err;
300 struct vnode *rvp = NULL;
301 struct vnode *videovp = NULL;
302 struct componentname cn;
303 struct vfs_context context;
304 char dirname[] = "MPEGAV";
305
306 result = 0;
307
308 err = cd9660_root(isomp->im_mountp, &rvp, NULL);
309 if (err) {
310 printf("cd9660_find_video_dir: cd9660_root failed (%d)\n", err);
311 return 0;
312 }
313
314 context.vc_proc = current_proc();
315 context.vc_ucred = kauth_cred_get();
316
317 cn.cn_nameiop = LOOKUP;
318 cn.cn_flags = ISLASTCN;
319 cn.cn_context = &context;
320 cn.cn_pnbuf = dirname;
321 cn.cn_pnlen = sizeof(dirname)-1;
322 cn.cn_nameptr = cn.cn_pnbuf;
323 cn.cn_namelen = cn.cn_pnlen;
324
325 err = VNOP_LOOKUP(rvp, &videovp, &cn, &context);
326 if (err == 0) {
327 struct iso_node *ip = VTOI(videovp);
328 result = 1;
329 isomp->video_dir_start = ip->iso_start;
330 isomp->video_dir_end = ip->iso_start + (ip->i_size >> isomp->im_bshift);
331 isomp->im_flags2 |= IMF2_IS_VCD;
332
333 vnode_put(videovp);
334 }
335 vnode_put(rvp);
336
337 return result;
338}
339
340
341
342
343static int
344iso_mountfs(devvp, mp, argp, context)
345 register struct vnode *devvp;
346 struct mount *mp;
347 struct user_iso_args *argp;
348 vfs_context_t context;
349{
350 struct proc *p;
351 register struct iso_mnt *isomp = (struct iso_mnt *)0;
352 struct buf *bp = NULL;
353 struct buf *pribp = NULL, *supbp = NULL;
354 dev_t dev = vnode_specrdev(devvp);
355 int error = EINVAL;
356 int breaderr = 0;
357 u_long iso_bsize;
358 int iso_blknum;
359 int joliet_level;
360 struct iso_volume_descriptor *vdp = NULL;
361 struct iso_primary_descriptor *pri = NULL;
362 struct iso_primary_descriptor *sup = NULL;
363 struct iso_directory_record *rootp;
364 int logical_block_size;
365 u_int8_t vdtype;
366 int blkoff = argp->ssector;
367
368 if (vfs_isrdwr(mp))
369 return (EROFS);
370
371
372
373
374
375 iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
376
377
378 if ((error = VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
379 (caddr_t)&iso_bsize, FWRITE, context)))
380 return (error);
381
382 joliet_level = 0;
383 for (iso_blknum = 16 + blkoff; iso_blknum < (100 + blkoff); iso_blknum++) {
384 if ((error = (int)buf_bread(devvp, (daddr64_t)((unsigned)iso_blknum), iso_bsize, NOCRED, &bp))) {
385 if (bp) {
386 buf_markaged(bp);
387 buf_brelse(bp);
388 bp = NULL;
389 }
390 breaderr = error;
391 printf("iso_mountfs: buf_bread error %d reading block %d\n", error, iso_blknum);
392 continue;
393 }
394
395 vdp = (struct iso_volume_descriptor *)buf_dataptr(bp);
396 if (bcmp (vdp->volume_desc_id, ISO_STANDARD_ID, sizeof(vdp->volume_desc_id)) != 0) {
397#ifdef DEBUG
398 printf("cd9660_vfsops.c: iso_mountfs: "
399 "Invalid ID in volume desciptor.\n");
400#endif
401
402
403
404
405
406
407
408 if (pri != NULL)
409 break;
410
411 error = EINVAL;
412 goto out;
413 }
414
415 vdtype = isonum_711 (vdp->type);
416 if (vdtype == ISO_VD_END)
417 break;
418
419 if (vdtype == ISO_VD_PRIMARY) {
420 if (pribp == NULL) {
421 pribp = bp;
422 bp = NULL;
423 pri = (struct iso_primary_descriptor *)vdp;
424 }
425 } else if(vdtype == ISO_VD_SUPPLEMENTARY) {
426 if (supbp == NULL) {
427 supbp = bp;
428 bp = NULL;
429 sup = (struct iso_primary_descriptor *)vdp;
430
431 if ((argp->flags & ISOFSMNT_NOJOLIET) == 0) {
432
433
434
435
436
437 if (bcmp(sup->escape_seq, ISO_UCS2_Level_1, 3) == 0)
438 joliet_level = 1;
439 else if (bcmp(sup->escape_seq, ISO_UCS2_Level_2, 3) == 0)
440 joliet_level = 2;
441 else if (bcmp(sup->escape_seq, ISO_UCS2_Level_3, 3) == 0)
442 joliet_level = 3;
443 }
444 }
445 }
446
447 if (bp) {
448 buf_markaged(bp);
449 buf_brelse(bp);
450 bp = NULL;
451 }
452 }
453
454 if (bp) {
455 buf_markaged(bp);
456 buf_brelse(bp);
457 bp = NULL;
458 }
459
460 if (pri == NULL) {
461 if (breaderr)
462 error = breaderr;
463 else
464 error = EINVAL;
465 goto out;
466 }
467
468 logical_block_size = isonum_723 (pri->logical_block_size);
469
470 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
471 || (logical_block_size & (logical_block_size - 1)) != 0) {
472 error = EINVAL;
473 goto out;
474 }
475
476 rootp = (struct iso_directory_record *)pri->root_directory_record;
477
478 MALLOC(isomp, struct iso_mnt *, sizeof *isomp, M_ISOFSMNT, M_WAITOK);
479 bzero((caddr_t)isomp, sizeof *isomp);
480 isomp->im_sector_size = ISO_DEFAULT_BLOCK_SIZE;
481 isomp->logical_block_size = logical_block_size;
482 isomp->volume_space_size = isonum_733 (pri->volume_space_size);
483
484
485
486
487
488
489
490
491 isomp->volume_space_size += blkoff;
492 bcopy (rootp, isomp->root, sizeof isomp->root);
493 isomp->root_extent = isonum_733 (rootp->extent);
494 isomp->root_size = isonum_733 (rootp->size);
495
496
497
498
499
500
501 if ( strlen(pri->volume_id) ) {
502 char *myPtr;
503
504 myPtr = pri->volume_id + strlen( pri->volume_id ) - 1;
505 while ( *myPtr == ' ' && myPtr >= pri->volume_id ) {
506 *myPtr = 0x00;
507 myPtr--;
508 }
509 }
510
511 if (pri->volume_id[0] == 0)
512 strcpy(isomp->volume_id, ISO_DFLT_VOLUME_ID);
513 else
514 bcopy(pri->volume_id, isomp->volume_id, sizeof(isomp->volume_id));
515 cd9660_tstamp_conv17(pri->creation_date, &isomp->creation_date);
516 cd9660_tstamp_conv17(pri->modification_date, &isomp->modification_date);
517
518
519 if (bcmp( pri->CDXASignature, ISO_XA_ID,
520 sizeof(pri->CDXASignature) ) == 0 ) {
521 isomp->im_flags2 |= IMF2_IS_CDXA;
522 }
523
524 isomp->im_bmask = logical_block_size - 1;
525 isomp->im_bshift = 0;
526 while ((1 << isomp->im_bshift) < isomp->logical_block_size)
527 isomp->im_bshift++;
528
529 buf_markaged(pribp);
530 buf_brelse(pribp);
531 pribp = NULL;
532
533 vfs_setfsprivate(mp, (void *)isomp);
534 vfs_statfs(mp)->f_fsid.val[0] = (long)dev;
535 vfs_statfs(mp)->f_fsid.val[1] = vfs_typenum(mp);
536 vfs_setmaxsymlen(mp, 0);
537 vfs_setflags(mp, MNT_LOCAL);
538
539 isomp->im_mountp = mp;
540 isomp->im_dev = dev;
541 isomp->im_devvp = devvp;
542
543
544
545
546
547
548
549 if (logical_block_size != iso_bsize) {
550 iso_bsize = logical_block_size;
551 if ((error = VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
552 (caddr_t)&iso_bsize, FWRITE, context)))
553 goto out;
554 }
555
556
557 if (!(argp->flags & ISOFSMNT_NORRIP)) {
558 if ( (error = (int)buf_bread(isomp->im_devvp,
559 (daddr64_t)((unsigned)((isomp->root_extent + isonum_711(rootp->ext_attr_length)))),
560 isomp->logical_block_size, NOCRED, &bp)) ) {
561
562 printf("iso_mountfs: buf_bread error %d reading block %d\n",
563 error, isomp->root_extent + isonum_711(rootp->ext_attr_length));
564 argp->flags |= ISOFSMNT_NORRIP;
565 goto skipRRIP;
566 }
567 rootp = (struct iso_directory_record *)buf_dataptr(bp);
568
569 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
570 argp->flags |= ISOFSMNT_NORRIP;
571 } else {
572 argp->flags &= ~ISOFSMNT_GENS;
573 }
574
575
576
577
578
579 buf_markaged(bp);
580 buf_brelse(bp);
581 bp = NULL;
582 }
583skipRRIP:
584
585 isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
586 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET);
587
588 switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
589 default:
590 isomp->iso_ftype = ISO_FTYPE_DEFAULT;
591 break;
592 case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
593 isomp->iso_ftype = ISO_FTYPE_9660;
594 break;
595 case 0:
596 isomp->iso_ftype = ISO_FTYPE_RRIP;
597 break;
598 }
599
600
601
602 if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level != 0) {
603 char vol_id[32];
604 int i, convflags;
605 size_t convbytes;
606 u_int16_t *uchp;
607
608
609
610
611
612
613 convflags = UTF_DECOMPOSED;
614 if (BYTE_ORDER != BIG_ENDIAN)
615 convflags |= UTF_REVERSE_ENDIAN;
616 uchp = (u_int16_t *)sup->volume_id;
617 for (i = 0; i < 16 && uchp[i]; ++i);
618 if ((utf8_encodestr((u_int16_t *)sup->volume_id, (i * 2), vol_id,
619 &convbytes, sizeof(vol_id), 0, convflags) == 0)
620 && convbytes && (vol_id[0] != ' ')) {
621 char * strp;
622
623
624 strp = vol_id + convbytes - 1;
625 while (strp > vol_id && *strp == ' ')
626 *strp-- = '\0';
627 bcopy(vol_id, isomp->volume_id, convbytes + 1);
628 }
629
630 rootp = (struct iso_directory_record *)
631 sup->root_directory_record;
632 bcopy (rootp, isomp->root, sizeof isomp->root);
633 isomp->root_extent = isonum_733 (rootp->extent);
634 isomp->root_size = isonum_733 (rootp->size);
635 buf_markaged(supbp);
636 isomp->iso_ftype = ISO_FTYPE_JOLIET;
637 }
638
639 if (supbp) {
640 buf_brelse(supbp);
641 supbp = NULL;
642 }
643
644
645 if (argp->flags & ISOFSMNT_TOC) {
646 MALLOC(isomp->toc, struct CDTOC *, argp->toc_length, M_ISOFSMNT, M_WAITOK);
647 if ((error = copyin(argp->toc, isomp->toc, argp->toc_length)))
648 goto out;
649 }
650
651
652 if ((isomp->im_flags2 & IMF2_IS_CDXA) && cd9660_find_video_dir(isomp)) {
653
654 isomp->phys_devvp = cd9660_phys_device(mp, context);
655 }
656
657
658 (void) cd9660_statfs(mp, vfs_statfs(mp), context);
659
660 return (0);
661out:
662 if (bp)
663 buf_brelse(bp);
664 if (pribp)
665 buf_brelse(pribp);
666 if (supbp)
667 buf_brelse(supbp);
668
669 if (isomp) {
670 if (isomp->toc)
671 FREE((caddr_t)isomp->toc, M_ISOFSMNT);
672 FREE((caddr_t)isomp, M_ISOFSMNT);
673
674 vfs_setfsprivate(mp, (void *)0);
675 }
676 return (error);
677}
678
679
680
681
682
683
684int
685cd9660_start(__unused struct mount *mp, __unused int flags,
686 __unused vfs_context_t context)
687{
688 return (0);
689}
690
691
692
693
694int
695cd9660_unmount(struct mount *mp, int mntflags, vfs_context_t context)
696{
697 register struct iso_mnt *isomp;
698 int error, flags = 0;
699 int force = 0;
700
701 if ( (mntflags & MNT_FORCE) ) {
702 flags |= FORCECLOSE;
703 force = 1;
704 }
705
706 if ( (error = vflush(mp, NULLVP, flags)) && !force )
707 return (error);
708
709 isomp = VFSTOISOFS(mp);
710
711#ifdef ISODEVMAP
712 if (isomp->iso_ftype == ISO_FTYPE_RRIP)
713 iso_dunmap(isomp->im_dev);
714#endif
715 if (isomp->phys_devvp) {
716 error = VNOP_CLOSE(isomp->phys_devvp, FREAD, context);
717 if (error && !force)
718 return error;
719 vnode_put(isomp->phys_devvp);
720 }
721
722 if (isomp->toc)
723 FREE((caddr_t)isomp->toc, M_ISOFSMNT);
724 FREE((caddr_t)isomp, M_ISOFSMNT);
725
726 return (0);
727}
728
729
730
731
732int
733cd9660_root(struct mount *mp, struct vnode **vpp, __unused vfs_context_t context)
734{
735 struct iso_mnt *imp = VFSTOISOFS(mp);
736 struct iso_directory_record *dp =
737 (struct iso_directory_record *)imp->root;
738 ino_t ino = isodirino(dp, imp);
739
740
741
742
743
744 return (cd9660_vget_internal(mp, ino, vpp, NULL, NULL,
745 imp->iso_ftype == ISO_FTYPE_RRIP, dp, current_proc()));
746}
747
748
749
750
751
752int
753cd9660_statfs(struct mount *mp, register struct vfsstatfs *sbp,
754 __unused vfs_context_t context)
755{
756 register struct iso_mnt *isomp;
757
758 isomp = VFSTOISOFS(mp);
759
760#if 0
761#ifdef COMPAT_09
762 sbp->f_type = 5;
763#else
764 sbp->f_type = 0;
765#endif
766#endif
767 sbp->f_bsize = (uint32_t)isomp->logical_block_size;
768 sbp->f_iosize = (size_t)sbp->f_bsize;
769 sbp->f_blocks = (uint64_t)((unsigned long)isomp->volume_space_size);
770 sbp->f_bfree = (uint64_t)0;
771 sbp->f_bavail = (uint64_t)0;
772 sbp->f_files = (uint64_t)0;
773 sbp->f_ffree = (uint64_t)0;
774 sbp->f_fstypename[(MFSTYPENAMELEN - 1)] = '\0';
775
776
777
778
779
780
781
782 if (isomp->iso_ftype == ISO_FTYPE_JOLIET)
783 sbp->f_fssubtype = 1;
784 else if (isomp->iso_ftype == ISO_FTYPE_RRIP)
785 sbp->f_fssubtype = 2;
786 else
787 sbp->f_fssubtype = 0;
788
789
790
791
792 return (0);
793}
794
795int cd9660_vfs_getattr(struct mount *mp, struct vfs_attr *fsap, vfs_context_t context)
796{
797 struct iso_mnt *imp;
798 struct vfsstatfs *stats = vfs_statfs(mp);
799
800 imp = VFSTOISOFS(mp);
801
802
803
804
805
806
807
808 VFSATTR_RETURN(fsap, f_iosize, stats->f_iosize);
809 VFSATTR_RETURN(fsap, f_blocks, stats->f_blocks);
810 VFSATTR_RETURN(fsap, f_bfree, stats->f_bfree);
811 VFSATTR_RETURN(fsap, f_bavail, stats->f_bavail);
812 VFSATTR_RETURN(fsap, f_bused, stats->f_blocks);
813
814
815
816
817
818
819
820 if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) {
821 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] =
822 (imp->iso_ftype == ISO_FTYPE_RRIP ? VOL_CAP_FMT_SYMBOLICLINKS : 0) |
823 (imp->iso_ftype == ISO_FTYPE_RRIP ? VOL_CAP_FMT_HARDLINKS : 0) |
824 (imp->iso_ftype == ISO_FTYPE_RRIP || imp->iso_ftype == ISO_FTYPE_JOLIET
825 ? VOL_CAP_FMT_CASE_SENSITIVE : 0) |
826 VOL_CAP_FMT_CASE_PRESERVING |
827 VOL_CAP_FMT_FAST_STATFS;
828 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] =
829 VOL_CAP_INT_ATTRLIST |
830 VOL_CAP_INT_NFSEXPORT;
831 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
832 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
833
834 fsap->f_capabilities.valid[VOL_CAPABILITIES_FORMAT] =
835 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
836 VOL_CAP_FMT_SYMBOLICLINKS |
837 VOL_CAP_FMT_HARDLINKS |
838 VOL_CAP_FMT_JOURNAL |
839 VOL_CAP_FMT_JOURNAL_ACTIVE |
840 VOL_CAP_FMT_NO_ROOT_TIMES |
841 VOL_CAP_FMT_SPARSE_FILES |
842 VOL_CAP_FMT_ZERO_RUNS |
843 VOL_CAP_FMT_CASE_SENSITIVE |
844 VOL_CAP_FMT_CASE_PRESERVING |
845 VOL_CAP_FMT_FAST_STATFS |
846 VOL_CAP_FMT_2TB_FILESIZE;
847 fsap->f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] =
848 VOL_CAP_INT_SEARCHFS |
849 VOL_CAP_INT_ATTRLIST |
850 VOL_CAP_INT_NFSEXPORT |
851 VOL_CAP_INT_READDIRATTR |
852 VOL_CAP_INT_EXCHANGEDATA |
853 VOL_CAP_INT_COPYFILE |
854 VOL_CAP_INT_ALLOCATE |
855 VOL_CAP_INT_VOL_RENAME |
856 VOL_CAP_INT_ADVLOCK |
857 VOL_CAP_INT_FLOCK;
858 fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0;
859 fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0;
860
861 VFSATTR_SET_SUPPORTED(fsap, f_capabilities);
862 }
863
864 if (VFSATTR_IS_ACTIVE(fsap, f_attributes)) {
865
866
867
868
869
870
871 fsap->f_attributes.validattr.commonattr = ATTR_CMN_VALIDMASK;
872 fsap->f_attributes.validattr.volattr = ATTR_VOL_VALIDMASK;
873 fsap->f_attributes.validattr.dirattr = ATTR_DIR_VALIDMASK;
874 fsap->f_attributes.validattr.fileattr = ATTR_FILE_VALIDMASK;
875 fsap->f_attributes.validattr.forkattr = ATTR_FORK_VALIDMASK;
876
877 fsap->f_attributes.nativeattr.commonattr = ATTR_CMN_VALIDMASK;
878 fsap->f_attributes.nativeattr.volattr = ATTR_VOL_VALIDMASK;
879 fsap->f_attributes.nativeattr.dirattr = ATTR_DIR_VALIDMASK;
880 fsap->f_attributes.nativeattr.fileattr = ATTR_FILE_VALIDMASK;
881 fsap->f_attributes.nativeattr.forkattr = ATTR_FORK_VALIDMASK;
882
883 VFSATTR_SET_SUPPORTED(fsap, f_attributes);
884 }
885
886 VFSATTR_RETURN(fsap, f_create_time, imp->creation_date);
887 VFSATTR_RETURN(fsap, f_modify_time, imp->modification_date);
888
889
890
891 return 0;
892}
893
894
895int
896cd9660_sync(__unused struct mount *mp, __unused int waitfor,
897 __unused vfs_context_t context)
898{
899
900 return (0);
901}
902
903
904
905
906
907
908
909
910
911
912
913struct ifid {
914 int ifid_ino;
915 long ifid_start;
916};
917
918
919int
920cd9660_fhtovp(mount_t mp, int fhlen, unsigned char *fhp, vnode_t *vpp, vfs_context_t context)
921{
922 struct ifid *ifhp = (struct ifid *)fhp;
923 register struct iso_node *ip;
924 struct vnode *nvp;
925 int error;
926
927 if (fhlen < (int)sizeof(struct ifid))
928 return (EINVAL);
929
930#ifdef ISOFS_DBG
931 printf("fhtovp: ino %d, start %ld\n",
932 ifhp->ifid_ino, ifhp->ifid_start);
933#endif
934
935 if ( (error = VFS_VGET(mp, (ino64_t)ifhp->ifid_ino, &nvp, context)) ) {
936 *vpp = NULLVP;
937 return (error);
938 }
939 ip = VTOI(nvp);
940 if (ip->inode.iso_mode == 0) {
941 vnode_put(nvp);
942 *vpp = NULLVP;
943 return (ESTALE);
944 }
945 *vpp = nvp;
946 return (0);
947}
948
949
950
951
952
953
954static int
955cd9660_track_for_sector(struct CDTOC *toc, u_int sector)
956{
957 int i, tracks, result;
958
959 if (toc == NULL)
960 return -1;
961
962 tracks = toc->length / sizeof(struct CDTOC_Desc);
963
964 result = -1;
965 for (i=0; i<tracks; ++i) {
966 if (toc->trackdesc[i].point < 100 && MSF_TO_LBA(toc->trackdesc[i].p) <= sector) {
967 result = toc->trackdesc[i].point;
968 }
969 }
970
971 return result;
972}
973
974
975
976
977
978static int
979cd9660_is_video_file(struct iso_node *ip, struct iso_mnt *imp)
980{
981 int lbn;
982 int track;
983
984
985 if (((imp->im_flags2 & IMF2_IS_VCD) == 0) ||
986 imp->phys_devvp == NULL ||
987 imp->toc == NULL)
988 {
989 return 0;
990 }
991
992
993 if ((ip->inode.iso_mode & S_IFMT) != S_IFREG)
994 return 0;
995
996
997
998
999
1000
1001
1002 lbn = lblkno(imp, ip->i_number);
1003 if (lbn < imp->video_dir_start || lbn >= imp->video_dir_end)
1004 return 0;
1005
1006
1007
1008
1009
1010
1011 if (strlen(ip->i_namep) != 11 ||
1012 bcmp(ip->i_namep+7, ".DAT", 4) ||
1013 (bcmp(ip->i_namep, "AVSEQ", 5) &&
1014 bcmp(ip->i_namep, "MUSIC", 5)))
1015 {
1016 return 0;
1017 }
1018
1019
1020
1021
1022
1023
1024
1025 track = (ip->i_namep[5] - '0') * 10 + ip->i_namep[6] - '0';
1026 if (track != (cd9660_track_for_sector(imp->toc, ip->iso_start) - 1))
1027 {
1028 return 0;
1029 }
1030
1031
1032 return 1;
1033}
1034
1035int
1036cd9660_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, __unused vfs_context_t context)
1037{
1038
1039
1040
1041
1042
1043
1044
1045 return ( cd9660_vget_internal( mp, (ino_t)ino, vpp, NULL, NULL,
1046 0, (struct iso_directory_record *) 0, current_proc()) );
1047}
1048
1049int
1050cd9660_vget_internal(mount_t mp, ino_t ino, vnode_t *vpp, vnode_t dvp,
1051 struct componentname *cnp, int relocated,
1052 struct iso_directory_record *isodir, proc_t p)
1053{
1054 register struct iso_mnt *imp;
1055 struct iso_node *ip;
1056 buf_t bp = NULL;
1057 vnode_t vp;
1058 dev_t dev;
1059 int error;
1060 struct vnode_fsparam vfsp;
1061 enum vtype vtype;
1062 int is_video_file = 0;
1063
1064 *vpp = NULLVP;
1065 imp = VFSTOISOFS(mp);
1066 dev = imp->im_dev;
1067#if 0
1068
1069 if (mp->mnt_kern_flag & MNTK_UNMOUNT)
1070 return (EPERM);
1071#endif
1072
1073 MALLOC_ZONE(ip, struct iso_node *, sizeof(struct iso_node),
1074 M_ISOFSNODE, M_WAITOK);
1075
1076
1077
1078
1079
1080
1081
1082 if ((*vpp = cd9660_ihashget(dev, ino, p)) != NULLVP) {
1083 FREE_ZONE(ip, sizeof(struct iso_node), M_ISOFSNODE);
1084 return (0);
1085 }
1086 bzero((caddr_t)ip, sizeof(struct iso_node));
1087
1088 ip->i_dev = dev;
1089 ip->i_number = ino;
1090 ip->i_namep = &isonullname[0];
1091 ip->i_mnt = imp;
1092 ip->i_devvp = imp->im_devvp;
1093
1094 SET(ip->i_flag, ISO_INALLOC);
1095
1096
1097
1098
1099
1100
1101 cd9660_ihashins(ip);
1102
1103 if (isodir == 0) {
1104 int lbn, off;
1105
1106 lbn = lblkno(imp, ino);
1107
1108 if (lbn >= imp->volume_space_size) {
1109 printf("fhtovp: lbn exceed volume space %d\n", lbn);
1110 error = ESTALE;
1111 goto errout;
1112 }
1113 off = blkoff(imp, ino);
1114
1115 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
1116 printf("fhtovp: crosses block boundary %d\n",
1117 off + ISO_DIRECTORY_RECORD_SIZE);
1118 error = ESTALE;
1119 goto errout;
1120 }
1121
1122 error = (int)buf_bread(imp->im_devvp, (daddr64_t)((unsigned)lbn),
1123 imp->logical_block_size, NOCRED, &bp);
1124 if (error) {
1125 printf("fhtovp: buf_bread error %d\n",error);
1126 goto errout;
1127 }
1128 isodir = (struct iso_directory_record *)(buf_dataptr(bp) + off);
1129
1130 if (off + isonum_711(isodir->length) > imp->logical_block_size) {
1131 printf("fhtovp: directory crosses block boundary "
1132 "%d[off=%d/len=%d]\n",
1133 off +isonum_711(isodir->length), off,
1134 isonum_711(isodir->length));
1135 error = ESTALE;
1136 goto errout;
1137 }
1138
1139
1140
1141
1142
1143 if ((isonum_711(isodir->flags) & directoryBit)
1144 && (isodir->name[0] == 0)) {
1145 struct iso_directory_record *pdp;
1146
1147 pdp = (struct iso_directory_record *)
1148 ((char *)buf_dataptr(bp) + isonum_711(isodir->length));
1149 if ((isonum_711(pdp->flags) & directoryBit)
1150 && (pdp->name[0] == 1))
1151 ip->i_parent = isodirino(pdp, imp);
1152 }
1153 }
1154 if (relocated) {
1155 daddr64_t lbn;
1156
1157 if (bp) {
1158 buf_brelse(bp);
1159 bp = NULL;
1160 }
1161
1162
1163
1164
1165 ip->iso_start = ino >> imp->im_bshift;
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176 lbn = (daddr64_t)((unsigned)ip->iso_start) + 0;
1177
1178 if ((error = (int)buf_bread(imp->im_devvp, lbn, imp->im_sector_size, NOCRED, &bp)))
1179 goto errout;
1180
1181 isodir = (struct iso_directory_record *)buf_dataptr(bp);
1182 }
1183
1184
1185
1186
1187
1188 if ( ((isonum_711( isodir->flags ) & directoryBit) == 0) &&
1189 (imp->iso_ftype != ISO_FTYPE_RRIP) ) {
1190
1191 DRGetTypeCreatorAndFlags(imp, isodir, &ip->i_FileType,
1192 &ip->i_Creator, &ip->i_FinderFlags);
1193
1194 if (isonum_711(isodir->flags) & associatedBit)
1195 ip->i_flag |= ISO_ASSOCIATED;
1196 }
1197
1198
1199
1200
1201 if (isonum_711(isodir->flags) & existenceBit) {
1202 ip->i_FinderFlags |= fInvisibleBit;
1203 }
1204
1205 ip->iso_extent = isonum_733(isodir->extent);
1206 ip->i_size = isonum_733(isodir->size);
1207 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
1208
1209
1210
1211 if (ip->i_flag & ISO_ASSOCIATED)
1212 ip->i_size += ADH_SIZE;
1213
1214
1215
1216
1217 if (isonum_711(isodir->name_len) != 0) {
1218 u_char *utf8namep;
1219 u_short namelen;
1220 ino_t inump = 0;
1221
1222 MALLOC(utf8namep, u_char *, ISO_RRIP_NAMEMAX + 1, M_TEMP, M_WAITOK);
1223 namelen = isonum_711(isodir->name_len);
1224
1225 switch (imp->iso_ftype) {
1226 case ISO_FTYPE_RRIP:
1227 cd9660_rrip_getname(isodir, utf8namep, &namelen, &inump, imp);
1228 break;
1229
1230 case ISO_FTYPE_JOLIET:
1231 ucsfntrans((u_int16_t *)isodir->name, namelen,
1232 utf8namep, &namelen,
1233 isonum_711(isodir->flags) & directoryBit, ip->i_flag & ISO_ASSOCIATED);
1234 break;
1235
1236 default:
1237 isofntrans (isodir->name, namelen,
1238 utf8namep, &namelen,
1239 imp->iso_ftype == ISO_FTYPE_9660, ip->i_flag & ISO_ASSOCIATED);
1240 }
1241
1242 utf8namep[namelen] = '\0';
1243 MALLOC(ip->i_namep, u_char *, namelen + 1, M_TEMP, M_WAITOK);
1244 bcopy(utf8namep, ip->i_namep, namelen + 1);
1245 FREE(utf8namep, M_TEMP);
1246 }
1247
1248
1249
1250
1251 switch (imp->iso_ftype) {
1252 default:
1253 {
1254 buf_t bp2 = NULL;
1255 daddr64_t lbn;
1256 int off;
1257
1258 if ((imp->im_flags & ISOFSMNT_EXTATT) && (off = isonum_711(isodir->ext_attr_length))) {
1259
1260 lbn = (daddr64_t)((unsigned)ip->iso_start - off);
1261
1262 if ((error = (int)buf_bread(imp->im_devvp, lbn, imp->im_sector_size, NOCRED, &bp2))) {
1263 if (bp2)
1264 buf_brelse(bp2);
1265 goto errout;
1266 }
1267 } else
1268 bp2 = NULL;
1269
1270 cd9660_defattr(isodir, ip, bp2);
1271 cd9660_deftstamp(isodir, ip, bp2);
1272
1273 if (bp2)
1274 buf_brelse(bp2);
1275 break;
1276 }
1277 case ISO_FTYPE_RRIP:
1278 cd9660_rrip_analyze(isodir, ip, imp);
1279 break;
1280 }
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292 if (cd9660_is_video_file(ip, imp))
1293 {
1294 cd9660_xa_init(ip, isodir);
1295
1296 is_video_file = 1;
1297 }
1298 if (ip->iso_extent == imp->root_extent) {
1299 ip->i_parent = 1;
1300
1301 ip->inode.iso_mode = (ip->inode.iso_mode & ~S_IFMT) | S_IFDIR;
1302 }
1303 vtype = IFTOVT(ip->inode.iso_mode);
1304#if !FIFO
1305 if (vtype == VFIFO) {
1306 error = ENOTSUP;
1307 goto errout;
1308 }
1309#endif
1310#ifdef ISODEVMAP
1311 if (vtype == VCHR || vtype == VBLK) {
1312 struct iso_dnode *dp;
1313
1314 if (dp = iso_dmap(dev, ino, 0))
1315 ip->inode.iso_rdev = dp->d_dev;
1316 }
1317#endif
1318
1319
1320
1321
1322 vfsp.vnfs_mp = mp;
1323 vfsp.vnfs_vtype = vtype;
1324 vfsp.vnfs_str = "cd9660";
1325 vfsp.vnfs_dvp = dvp;
1326 vfsp.vnfs_fsnode = ip;
1327 vfsp.vnfs_cnp = cnp;
1328
1329 if (is_video_file)
1330 vfsp.vnfs_vops = cd9660_cdxaop_p;
1331 else if (vtype == VFIFO )
1332 vfsp.vnfs_vops = cd9660_fifoop_p;
1333 else if (vtype == VBLK || vtype == VCHR)
1334 vfsp.vnfs_vops = cd9660_specop_p;
1335 else
1336 vfsp.vnfs_vops = cd9660_vnodeop_p;
1337
1338 if (vtype == VBLK || vtype == VCHR)
1339 vfsp.vnfs_rdev = ip->inode.iso_rdev;
1340 else
1341 vfsp.vnfs_rdev = 0;
1342
1343 vfsp.vnfs_filesize = ip->i_size;
1344
1345 if (dvp && cnp && (cnp->cn_flags & MAKEENTRY))
1346 vfsp.vnfs_flags = 0;
1347 else
1348 vfsp.vnfs_flags = VNFS_NOCACHE;
1349
1350
1351 if (ip->iso_extent == imp->root_extent)
1352 vfsp.vnfs_markroot = 1;
1353 else
1354 vfsp.vnfs_markroot = 0;
1355
1356 vfsp.vnfs_marksystem = 0;
1357
1358 if ( (error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &vp)) )
1359 goto errout;
1360
1361 ip->i_vnode = vp;
1362
1363 vnode_ref(ip->i_devvp);
1364 vnode_addfsref(vp);
1365 vnode_settag(vp, VT_ISOFS);
1366
1367 if (bp)
1368 buf_brelse(bp);
1369 *vpp = vp;
1370
1371 CLR(ip->i_flag, ISO_INALLOC);
1372
1373 if (ISSET(ip->i_flag, ISO_INWALLOC))
1374 wakeup(ip);
1375
1376 return (0);
1377
1378errout:
1379 if (bp)
1380 buf_brelse(bp);
1381 cd9660_ihashrem(ip);
1382
1383 if (ISSET(ip->i_flag, ISO_INWALLOC))
1384 wakeup(ip);
1385
1386 FREE_ZONE(ip, sizeof(struct iso_node), M_ISOFSNODE);
1387
1388 return (error);
1389}
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426static void
1427DRGetTypeCreatorAndFlags( struct iso_mnt * theMountPointPtr,
1428 struct iso_directory_record * theDirRecPtr,
1429 u_int32_t * theTypePtr,
1430 u_int32_t * theCreatorPtr,
1431 u_int16_t * theFlagsPtr )
1432{
1433 int foundStuff;
1434 u_int32_t myType;
1435 u_int32_t myCreator;
1436 AppleExtension *myAppleExtPtr;
1437 NewAppleExtension *myNewAppleExtPtr;
1438 u_int16_t myFinderFlags;
1439 char *myPtr;
1440
1441 foundStuff = 1;
1442 myType = 0x3f3f3f3f;
1443 myCreator = 0x3f3f3f3f;
1444 myFinderFlags = 0;
1445 *theFlagsPtr = 0x0000;
1446
1447
1448
1449
1450
1451
1452 myPtr = &theDirRecPtr->name[ (isonum_711(theDirRecPtr->name_len)) ];
1453
1454
1455 if ( ((isonum_711(theDirRecPtr->name_len)) & 0x01) == 0 )
1456 myPtr++;
1457 myAppleExtPtr = (AppleExtension *) myPtr;
1458
1459
1460
1461
1462
1463 if ( (isonum_711(theDirRecPtr->length)) <=
1464 ISO_DIRECTORY_RECORD_SIZE + (isonum_711(theDirRecPtr->name_len)) ) {
1465 foundStuff = 0;
1466 goto DoneLooking;
1467 }
1468
1469 foundStuff = 0;
1470 myPtr = (char *) myAppleExtPtr;
1471
1472 if ( (theMountPointPtr->im_flags2 & IMF2_IS_CDXA) != 0 )
1473 myPtr += 14;
1474 myNewAppleExtPtr = (NewAppleExtension *) myPtr;
1475
1476
1477
1478
1479
1480
1481
1482 myPtr = ((char *) theDirRecPtr) + (isonum_711(theDirRecPtr->length));
1483 myPtr -= sizeof(NewAppleExtension) - 1;
1484 while( (char *) myNewAppleExtPtr < myPtr )
1485 {
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509 u_char *myFromPtr, *myToPtr;
1510 union
1511 {
1512 u_int32_t fourchars;
1513 u_char chars[4];
1514 } myChars;
1515
1516 if ( (myNewAppleExtPtr->signature[0] == 'A') &&
1517 (myNewAppleExtPtr->signature[1] == 'A') ) {
1518 if ( isonum_711(myNewAppleExtPtr->systemUseID) == 2 ) {
1519
1520 foundStuff = 1;
1521
1522 myFromPtr = &myNewAppleExtPtr->fileType[0];
1523 myToPtr = &myChars.chars[0];
1524 *myToPtr++ = *myFromPtr++;
1525 *myToPtr++ = *myFromPtr++;
1526 *myToPtr++ = *myFromPtr++;
1527 *myToPtr = *myFromPtr;
1528 myType = myChars.fourchars;
1529
1530 myFromPtr = &myNewAppleExtPtr->fileCreator[0];
1531 myToPtr = &myChars.chars[0];
1532 *myToPtr++ = *myFromPtr++;
1533 *myToPtr++ = *myFromPtr++;
1534 *myToPtr++ = *myFromPtr++;
1535 *myToPtr = *myFromPtr;
1536 myCreator = myChars.fourchars;
1537
1538 myFromPtr = &myNewAppleExtPtr->finderFlags[0];
1539 myToPtr = &myChars.chars[2];
1540 myChars.fourchars = 0;
1541 *myToPtr++ = *myFromPtr++;
1542 *myToPtr = *myFromPtr;
1543 myFinderFlags = myChars.fourchars;
1544 myFinderFlags &=
1545 ( fAlwaysBit | fSystemBit | fHasBundleBit | fLockedBit );
1546
1547 *theFlagsPtr = (myFinderFlags | fInitedBit);
1548
1549 break;
1550 }
1551 }
1552
1553
1554
1555
1556
1557
1558 if ( (isonum_711(myNewAppleExtPtr->OSULength)) < 4 )
1559 break;
1560
1561
1562 (char *)myNewAppleExtPtr += (isonum_711(myNewAppleExtPtr->OSULength));
1563
1564 }
1565
1566DoneLooking:
1567 if ( foundStuff != 0 ) {
1568 *theTypePtr = myType;
1569 *theCreatorPtr = myCreator;
1570 } else {
1571 *theTypePtr = 0;
1572 *theCreatorPtr = 0;
1573 }
1574
1575 return;
1576
1577}
1578
1579
1580
1581
1582
1583
1584int
1585cd9660_vptofh(struct vnode *vp, int *fhlenp, unsigned char *fhp, __unused vfs_context_t context)
1586{
1587 register struct iso_node *ip = VTOI(vp);
1588 register struct ifid *ifhp;
1589
1590 if (*fhlenp < (int)sizeof(struct ifid))
1591 return (EOVERFLOW);
1592
1593 ifhp = (struct ifid *)fhp;
1594
1595 ifhp->ifid_ino = ip->i_number;
1596 ifhp->ifid_start = ip->iso_start;
1597 *fhlenp = sizeof(struct ifid);
1598
1599#ifdef ISOFS_DBG
1600 printf("vptofh: ino %d, start %ld\n",
1601 ifhp->ifid_ino,ifhp->ifid_start);
1602#endif
1603 return (0);
1604}
1605
1606
1607
1608
1609int
1610cd9660_sysctl(__unused int *name, __unused u_int namelen, __unused user_addr_t oldp,
1611 __unused size_t *oldlenp, __unused user_addr_t newp,
1612 __unused size_t newlen, __unused vfs_context_t context)
1613{
1614 return (ENOTSUP);
1615}
1616
1617