1 /* $NetBSD: cd9660_rrip.c,v 1.18 2015/03/28 19:24:05 maxv Exp $ */
4 * Copyright (c) 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley
8 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
9 * Support code is derived from software contributed to Berkeley
10 * by Atsushi Murai (amurai@spec.co.jp).
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#)cd9660_rrip.c 8.6 (Berkeley) 12/5/94
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: cd9660_rrip.c,v 1.18 2015/03/28 19:24:05 maxv Exp $");
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/namei.h>
47 #include <sys/vnode.h>
48 #include <sys/mount.h>
49 #include <sys/kernel.h>
51 #include <sys/kauth.h>
55 #include <fs/cd9660/iso.h>
56 #include <fs/cd9660/cd9660_extern.h>
57 #include <fs/cd9660/cd9660_node.h>
58 #include <fs/cd9660/cd9660_rrip.h>
59 #include <fs/cd9660/iso_rrip.h>
63 int (*func
)(void *, ISO_RRIP_ANALYZE
*);
64 void (*func2
)(void *, ISO_RRIP_ANALYZE
*);
68 static int cd9660_rrip_attr(void *, ISO_RRIP_ANALYZE
*);
69 static void cd9660_rrip_defattr(void *, ISO_RRIP_ANALYZE
*);
70 static int cd9660_rrip_slink(void *, ISO_RRIP_ANALYZE
*);
71 static int cd9660_rrip_altname(void *, ISO_RRIP_ANALYZE
*);
72 static void cd9660_rrip_defname(void *, ISO_RRIP_ANALYZE
*);
73 static int cd9660_rrip_pclink(void *, ISO_RRIP_ANALYZE
*);
74 static int cd9660_rrip_reldir(void *, ISO_RRIP_ANALYZE
*);
75 static int cd9660_rrip_tstamp(void *, ISO_RRIP_ANALYZE
*);
76 static void cd9660_rrip_deftstamp(void *, ISO_RRIP_ANALYZE
*);
77 static int cd9660_rrip_device(void *, ISO_RRIP_ANALYZE
*);
78 static int cd9660_rrip_idflag(void *, ISO_RRIP_ANALYZE
*);
79 static int cd9660_rrip_cont(void *, ISO_RRIP_ANALYZE
*);
80 static int cd9660_rrip_stop(void *, ISO_RRIP_ANALYZE
*);
81 static int cd9660_rrip_extref(void *, ISO_RRIP_ANALYZE
*);
82 static int cd9660_rrip_loop(struct iso_directory_record
*,
83 ISO_RRIP_ANALYZE
*, const RRIP_TABLE
*);
85 * POSIX file attribute
88 cd9660_rrip_attr(void *v
, ISO_RRIP_ANALYZE
*ana
)
92 ana
->inop
->inode
.iso_mode
= isonum_733(p
->mode
);
93 ana
->inop
->inode
.iso_uid
= isonum_733(p
->uid
);
94 ana
->inop
->inode
.iso_gid
= isonum_733(p
->gid
);
95 ana
->inop
->inode
.iso_links
= isonum_733(p
->links
);
96 ana
->fields
&= ~ISO_SUSP_ATTR
;
101 cd9660_rrip_defattr(void *v
, ISO_RRIP_ANALYZE
*ana
)
103 struct iso_directory_record
*isodir
= v
;
105 /* But this is a required field! */
106 printf("RRIP without PX field?\n");
107 cd9660_defattr(isodir
, ana
->inop
, NULL
);
114 cd9660_rrip_slink(void *v
, ISO_RRIP_ANALYZE
*ana
)
116 ISO_RRIP_SLINK
*p
= v
;
117 ISO_RRIP_SLINK_COMPONENT
*pcomp
;
118 ISO_RRIP_SLINK_COMPONENT
*pcompe
;
123 pcomp
= (ISO_RRIP_SLINK_COMPONENT
*)p
->component
;
124 pcompe
= (ISO_RRIP_SLINK_COMPONENT
*)
125 ((char *)p
+ isonum_711(p
->h
.length
));
127 outbuf
= ana
->outbuf
;
131 * Gathering a Symbolic name from each component with path
135 pcomp
= (ISO_RRIP_SLINK_COMPONENT
*)((char *)pcomp
+ ISO_RRIP_SLSIZ
136 + isonum_711(pcomp
->clen
))) {
139 if (len
< ana
->maxlen
) {
149 switch (*pcomp
->cflag
) {
151 case ISO_SUSP_CFLAG_CURRENT
:
152 /* Inserting Current */
156 case ISO_SUSP_CFLAG_PARENT
:
157 /* Inserting Parent */
161 case ISO_SUSP_CFLAG_ROOT
:
162 /* Inserting slash for ROOT */
163 /* start over from beginning(?) */
168 case ISO_SUSP_CFLAG_VOLROOT
:
169 /* Inserting a mount point i.e. "/cdrom" */
173 inbuf
= ana
->imp
->im_mountp
->mnt_stat
.f_mntonname
;
174 wlen
= strlen(inbuf
);
177 case ISO_SUSP_CFLAG_HOST
:
178 /* Inserting hostname i.e. "kurt.tools.de" */
183 case ISO_SUSP_CFLAG_CONTINUE
:
187 /* Inserting component */
188 wlen
= isonum_711(pcomp
->clen
);
192 printf("RRIP with incorrect flags?");
193 wlen
= ana
->maxlen
+ 1;
197 if (len
+ wlen
> ana
->maxlen
) {
198 /* indicate error to caller */
201 ana
->outbuf
-= *ana
->outlen
;
206 memcpy(outbuf
, inbuf
, wlen
);
210 ana
->outbuf
= outbuf
;
214 if (!isonum_711(p
->flags
)) {
215 ana
->fields
&= ~ISO_SUSP_SLINK
;
216 return ISO_SUSP_SLINK
;
225 cd9660_rrip_altname(void *v
, ISO_RRIP_ANALYZE
*ana
)
227 ISO_RRIP_ALTNAME
*p
= v
;
237 case ISO_SUSP_CFLAG_CURRENT
:
238 /* Inserting Current */
242 case ISO_SUSP_CFLAG_PARENT
:
243 /* Inserting Parent */
247 case ISO_SUSP_CFLAG_HOST
:
248 /* Inserting hostname i.e. "kurt.tools.de" */
253 case ISO_SUSP_CFLAG_CONTINUE
:
257 /* Inserting component */
258 wlen
= isonum_711(p
->h
.length
) - 5;
259 inbuf
= (char *)p
+ 5;
263 printf("RRIP with incorrect NM flags?\n");
264 wlen
= ana
->maxlen
+ 1;
268 if ((*ana
->outlen
+= wlen
) > ana
->maxlen
) {
269 /* treat as no name field */
270 ana
->fields
&= ~ISO_SUSP_ALTNAME
;
271 ana
->outbuf
-= *ana
->outlen
- wlen
;
276 memcpy(ana
->outbuf
, inbuf
, wlen
);
280 ana
->fields
&= ~ISO_SUSP_ALTNAME
;
281 return ISO_SUSP_ALTNAME
;
287 cd9660_rrip_defname(void *v
, ISO_RRIP_ANALYZE
*ana
)
289 struct iso_directory_record
*isodir
= v
;
291 isofntrans(isodir
->name
, isonum_711(isodir
->name_len
),
292 ana
->outbuf
, ana
->outlen
,
293 1, 0, isonum_711(isodir
->flags
) & 4,
294 ana
->imp
->im_joliet_level
);
295 switch (ana
->outbuf
[0]) {
299 ana
->outbuf
[0] = '.';
303 strlcpy(ana
->outbuf
, "..", ana
->maxlen
- *ana
->outlen
);
310 * Parent or Child Link
313 cd9660_rrip_pclink(void *v
, ISO_RRIP_ANALYZE
*ana
)
315 ISO_RRIP_CLINK
*p
= v
;
317 *ana
->inump
= isonum_733(p
->dir_loc
) << ana
->imp
->im_bshift
;
318 ana
->fields
&= ~(ISO_SUSP_CLINK
| ISO_SUSP_PLINK
);
319 return *p
->h
.type
== 'C' ? ISO_SUSP_CLINK
: ISO_SUSP_PLINK
;
323 * Relocated directory
327 cd9660_rrip_reldir(void *v
, ISO_RRIP_ANALYZE
*ana
)
329 /* special hack to make caller aware of RE field */
332 return ISO_SUSP_RELDIR
| ISO_SUSP_ALTNAME
333 | ISO_SUSP_CLINK
| ISO_SUSP_PLINK
;
337 cd9660_rrip_tstamp(void *v
, ISO_RRIP_ANALYZE
*ana
)
339 ISO_RRIP_TSTAMP
*p
= v
;
344 /* Check a format of time stamp (7bytes/17bytes) */
345 if (!(*p
->flags
& ISO_SUSP_TSTAMP_FORM17
)) {
346 if (*p
->flags
& ISO_SUSP_TSTAMP_CREAT
)
349 if (*p
->flags
& ISO_SUSP_TSTAMP_MODIFY
) {
350 cd9660_tstamp_conv7(ptime
, &ana
->inop
->inode
.iso_mtime
);
353 memset(&ana
->inop
->inode
.iso_mtime
, 0, sizeof(struct timespec
));
355 if (*p
->flags
& ISO_SUSP_TSTAMP_ACCESS
) {
356 cd9660_tstamp_conv7(ptime
, &ana
->inop
->inode
.iso_atime
);
359 ana
->inop
->inode
.iso_atime
= ana
->inop
->inode
.iso_mtime
;
361 if (*p
->flags
& ISO_SUSP_TSTAMP_ATTR
)
362 cd9660_tstamp_conv7(ptime
, &ana
->inop
->inode
.iso_ctime
);
364 ana
->inop
->inode
.iso_ctime
= ana
->inop
->inode
.iso_mtime
;
367 if (*p
->flags
& ISO_SUSP_TSTAMP_CREAT
)
370 if (*p
->flags
& ISO_SUSP_TSTAMP_MODIFY
) {
371 cd9660_tstamp_conv17(ptime
, &ana
->inop
->inode
.iso_mtime
);
374 memset(&ana
->inop
->inode
.iso_mtime
, 0, sizeof(struct timespec
));
376 if (*p
->flags
& ISO_SUSP_TSTAMP_ACCESS
) {
377 cd9660_tstamp_conv17(ptime
, &ana
->inop
->inode
.iso_atime
);
380 ana
->inop
->inode
.iso_atime
= ana
->inop
->inode
.iso_mtime
;
382 if (*p
->flags
& ISO_SUSP_TSTAMP_ATTR
)
383 cd9660_tstamp_conv17(ptime
, &ana
->inop
->inode
.iso_ctime
);
385 ana
->inop
->inode
.iso_ctime
= ana
->inop
->inode
.iso_mtime
;
388 ana
->fields
&= ~ISO_SUSP_TSTAMP
;
389 return ISO_SUSP_TSTAMP
;
393 cd9660_rrip_deftstamp(void *v
, ISO_RRIP_ANALYZE
*ana
)
395 struct iso_directory_record
*isodir
= v
;
397 cd9660_deftstamp(isodir
, ana
->inop
, NULL
);
404 cd9660_rrip_device(void *v
, ISO_RRIP_ANALYZE
*ana
)
406 ISO_RRIP_DEVICE
*p
= v
;
409 high
= isonum_733(p
->dev_t_high
);
410 low
= isonum_733(p
->dev_t_low
);
413 ana
->inop
->inode
.iso_rdev
= makedev(major(low
), minor(low
));
415 ana
->inop
->inode
.iso_rdev
= makedev(high
, minor(low
));
416 ana
->fields
&= ~ISO_SUSP_DEVICE
;
417 return ISO_SUSP_DEVICE
;
424 cd9660_rrip_idflag(void *v
, ISO_RRIP_ANALYZE
*ana
)
426 ISO_RRIP_IDFLAG
*p
= v
;
428 ana
->fields
&= isonum_711(p
->flags
) | ~0xff; /* don't touch high bits */
429 /* special handling of RE field */
430 if (ana
->fields
& ISO_SUSP_RELDIR
)
431 return cd9660_rrip_reldir(p
, ana
);
433 return ISO_SUSP_IDFLAG
;
437 * Continuation pointer
440 cd9660_rrip_cont(void *v
, ISO_RRIP_ANALYZE
*ana
)
442 ISO_RRIP_CONT
*p
= v
;
444 ana
->iso_ce_blk
= isonum_733(p
->location
);
445 ana
->iso_ce_off
= isonum_733(p
->offset
);
446 ana
->iso_ce_len
= isonum_733(p
->length
);
447 return ISO_SUSP_CONT
;
454 cd9660_rrip_stop(void *v
, ISO_RRIP_ANALYZE
*ana
)
456 return ISO_SUSP_STOP
;
460 * Extension reference
463 cd9660_rrip_extref(void *v
, ISO_RRIP_ANALYZE
*ana
)
465 ISO_RRIP_EXTREF
*p
= v
;
467 if (isonum_711(p
->version
) != 1)
469 if (isonum_711(p
->len_id
) != 9
470 && isonum_711(p
->len_id
) != 10)
472 if (isonum_711(p
->len_id
) == 9
473 && memcmp((char *)p
+ 8, "IEEE_1282", 9))
475 if (isonum_711(p
->len_id
) == 10
476 && memcmp((char *)p
+ 8, "IEEE_P1282", 10)
477 && memcmp((char *)p
+ 8, "RRIP_1991A", 10))
479 ana
->fields
&= ~ISO_SUSP_EXTREF
;
480 return ISO_SUSP_EXTREF
;
485 cd9660_rrip_loop(struct iso_directory_record
*isodir
, ISO_RRIP_ANALYZE
*ana
,
486 const RRIP_TABLE
*table
)
488 const RRIP_TABLE
*ptable
;
489 ISO_SUSP_HEADER
*phead
;
490 ISO_SUSP_HEADER
*pend
;
491 struct buf
*bp
= NULL
;
497 * Note: If name length is odd,
498 * it will be padded by 1 byte after the name
500 pwhead
= isodir
->name
+ isonum_711(isodir
->name_len
);
501 if (!(isonum_711(isodir
->name_len
) & 1))
503 isochar(isodir
->name
, pwhead
, ana
->imp
->im_joliet_level
, &c
);
505 /* If it's not the '.' entry of the root dir obey SP field */
506 if (c
!= 0 || isonum_733(isodir
->extent
) != ana
->imp
->root_extent
)
507 pwhead
+= ana
->imp
->rr_skip
;
509 pwhead
+= ana
->imp
->rr_skip0
;
511 phead
= (ISO_SUSP_HEADER
*)pwhead
;
512 pend
= (ISO_SUSP_HEADER
*)((char *)isodir
+ isonum_711(isodir
->length
));
518 * Note: "pend" should be more than one SUSP header
520 while (pend
>= phead
+ 1) {
521 if (isonum_711(phead
->version
) == 1) {
522 for (ptable
= table
; ptable
->func
; ptable
++) {
523 if (*phead
->type
== *ptable
->type
524 && phead
->type
[1] == ptable
->type
[1]) {
525 result
|= ptable
->func(phead
, ana
);
532 if (result
& ISO_SUSP_STOP
) {
533 result
&= ~ISO_SUSP_STOP
;
536 /* plausibility check */
537 if (isonum_711(phead
->length
) < sizeof(*phead
))
541 * Hopefully this works with newer versions, too
543 phead
= (ISO_SUSP_HEADER
*)((char *)phead
+ isonum_711(phead
->length
));
546 if (ana
->fields
&& ana
->iso_ce_len
) {
547 if (ana
->iso_ce_blk
>= ana
->imp
->volume_space_size
548 || ana
->iso_ce_off
+ ana
->iso_ce_len
> ana
->imp
->logical_block_size
549 || bread(ana
->imp
->im_devvp
,
550 ana
->iso_ce_blk
<< (ana
->imp
->im_bshift
- DEV_BSHIFT
),
551 ana
->imp
->logical_block_size
,
553 /* what to do now? */
555 phead
= (ISO_SUSP_HEADER
*)((char *)bp
->b_data
+ ana
->iso_ce_off
);
556 pend
= (ISO_SUSP_HEADER
*)((char *)phead
+ ana
->iso_ce_len
);
563 * If we don't find the Basic SUSP stuffs, just set default value
564 * (attribute/time stamp)
566 for (ptable
= table
; ptable
->func2
; ptable
++)
567 if (!(ptable
->result
& result
))
568 ptable
->func2(isodir
, ana
);
576 static const RRIP_TABLE rrip_table_analyze
[] = {
577 { "PX", cd9660_rrip_attr
, cd9660_rrip_defattr
, ISO_SUSP_ATTR
},
578 { "TF", cd9660_rrip_tstamp
, cd9660_rrip_deftstamp
, ISO_SUSP_TSTAMP
},
579 { "PN", cd9660_rrip_device
, 0, ISO_SUSP_DEVICE
},
580 { "RR", cd9660_rrip_idflag
, 0, ISO_SUSP_IDFLAG
},
581 { "CE", cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
582 { "ST", cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
587 cd9660_rrip_analyze(struct iso_directory_record
*isodir
, struct iso_node
*inop
,
590 ISO_RRIP_ANALYZE analyze
;
594 analyze
.fields
= ISO_SUSP_ATTR
| ISO_SUSP_TSTAMP
| ISO_SUSP_DEVICE
;
596 return cd9660_rrip_loop(isodir
, &analyze
, rrip_table_analyze
);
600 * Get Alternate Name.
602 static const RRIP_TABLE rrip_table_getname
[] = {
603 { "NM", cd9660_rrip_altname
, cd9660_rrip_defname
, ISO_SUSP_ALTNAME
},
604 { "CL", cd9660_rrip_pclink
, 0, ISO_SUSP_CLINK
|ISO_SUSP_PLINK
},
605 { "PL", cd9660_rrip_pclink
, 0, ISO_SUSP_CLINK
|ISO_SUSP_PLINK
},
606 { "RE", cd9660_rrip_reldir
, 0, ISO_SUSP_RELDIR
},
607 { "RR", cd9660_rrip_idflag
, 0, ISO_SUSP_IDFLAG
},
608 { "CE", cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
609 { "ST", cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
614 cd9660_rrip_getname(struct iso_directory_record
*isodir
, char *outbuf
,
615 u_short
*outlen
, ino_t
*inump
, struct iso_mnt
*imp
)
617 ISO_RRIP_ANALYZE analyze
;
618 const RRIP_TABLE
*tab
;
621 analyze
.outbuf
= outbuf
;
622 analyze
.outlen
= outlen
;
623 analyze
.maxlen
= ISO_MAXNAMLEN
;
624 analyze
.inump
= inump
;
626 analyze
.fields
= ISO_SUSP_ALTNAME
| ISO_SUSP_RELDIR
| ISO_SUSP_CLINK
| ISO_SUSP_PLINK
;
629 isochar(isodir
->name
, isodir
->name
+ isonum_711(isodir
->name_len
),
630 imp
->im_joliet_level
, &c
);
631 tab
= rrip_table_getname
;
632 if (c
== 0 || c
== 1) {
633 cd9660_rrip_defname(isodir
, &analyze
);
635 analyze
.fields
&= ~ISO_SUSP_ALTNAME
;
639 return cd9660_rrip_loop(isodir
, &analyze
, tab
);
645 static const RRIP_TABLE rrip_table_getsymname
[] = {
646 { "SL", cd9660_rrip_slink
, 0, ISO_SUSP_SLINK
},
647 { "RR", cd9660_rrip_idflag
, 0, ISO_SUSP_IDFLAG
},
648 { "CE", cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
649 { "ST", cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
654 cd9660_rrip_getsymname(struct iso_directory_record
*isodir
, char *outbuf
,
655 u_short
*outlen
, struct iso_mnt
*imp
)
657 ISO_RRIP_ANALYZE analyze
;
659 analyze
.outbuf
= outbuf
;
660 analyze
.outlen
= outlen
;
662 analyze
.maxlen
= MAXPATHLEN
;
663 analyze
.cont
= 1; /* don't start with a slash */
665 analyze
.fields
= ISO_SUSP_SLINK
;
667 return cd9660_rrip_loop(isodir
, &analyze
, rrip_table_getsymname
) & ISO_SUSP_SLINK
;
670 static const RRIP_TABLE rrip_table_extref
[] = {
671 { "ER", cd9660_rrip_extref
, 0, ISO_SUSP_EXTREF
},
672 { "CE", cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
673 { "ST", cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
678 * Check for Rock Ridge Extension and return offset of its fields.
679 * Note: We insist on the ER field.
682 cd9660_rrip_offset(struct iso_directory_record
*isodir
, struct iso_mnt
*imp
)
685 ISO_RRIP_ANALYZE analyze
;
688 p
= (ISO_RRIP_OFFSET
*)(isodir
->name
+ 1);
689 if (memcmp(p
, "SP\7\1\276\357", 6)) {
690 /* Maybe, it's a CDROM XA disc? */
692 p
= (ISO_RRIP_OFFSET
*)((char *)p
+ 15);
693 if (memcmp(p
, "SP\7\1\276\357", 6))
698 analyze
.fields
= ISO_SUSP_EXTREF
;
699 if (!(cd9660_rrip_loop(isodir
, &analyze
, rrip_table_extref
) & ISO_SUSP_EXTREF
))
702 return isonum_711(p
->skip
);