2 * Copyright (c) 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley
6 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
7 * Support code is derived from software contributed to Berkeley
8 * by Atsushi Murai (amurai@spec.co.jp).
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * @(#)cd9660_rrip.c 8.6 (Berkeley) 12/5/94
35 * $FreeBSD: src/sys/isofs/cd9660/cd9660_rrip.c,v 1.17 1999/08/28 00:46:06 peter Exp $
38 #include <sys/param.h>
39 #include <sys/systm.h>
41 #include <sys/vnode.h>
42 #include <sys/mount.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
47 #include "cd9660_node.h"
48 #include "cd9660_rrip.h"
53 typedef int rrt_func_t(void *, ISO_RRIP_ANALYZE
*ana
);
58 void (*func2
)(struct iso_directory_record
*isodir
, ISO_RRIP_ANALYZE
*ana
);
62 static int cd9660_rrip_altname(ISO_RRIP_ALTNAME
*p
, ISO_RRIP_ANALYZE
*ana
);
63 static int cd9660_rrip_attr(ISO_RRIP_ATTR
*p
, ISO_RRIP_ANALYZE
*ana
);
64 static int cd9660_rrip_cont(ISO_RRIP_CONT
*p
, ISO_RRIP_ANALYZE
*ana
);
65 static void cd9660_rrip_defattr(struct iso_directory_record
*isodir
,
66 ISO_RRIP_ANALYZE
*ana
);
67 static void cd9660_rrip_defname(struct iso_directory_record
*isodir
,
68 ISO_RRIP_ANALYZE
*ana
);
69 static void cd9660_rrip_deftstamp(struct iso_directory_record
*isodir
,
70 ISO_RRIP_ANALYZE
*ana
);
71 static int cd9660_rrip_device(ISO_RRIP_DEVICE
*p
, ISO_RRIP_ANALYZE
*ana
);
72 static int cd9660_rrip_extref(ISO_RRIP_EXTREF
*p
, ISO_RRIP_ANALYZE
*ana
);
73 static int cd9660_rrip_idflag(ISO_RRIP_IDFLAG
*p
, ISO_RRIP_ANALYZE
*ana
);
74 static int cd9660_rrip_loop(struct iso_directory_record
*isodir
,
75 ISO_RRIP_ANALYZE
*ana
, RRIP_TABLE
*table
);
76 static int cd9660_rrip_pclink(ISO_RRIP_CLINK
*p
, ISO_RRIP_ANALYZE
*ana
);
77 static int cd9660_rrip_reldir(ISO_RRIP_RELDIR
*p
, ISO_RRIP_ANALYZE
*ana
);
78 static int cd9660_rrip_slink(ISO_RRIP_SLINK
*p
, ISO_RRIP_ANALYZE
*ana
);
79 static int cd9660_rrip_stop(ISO_SUSP_HEADER
*p
, ISO_RRIP_ANALYZE
*ana
);
80 static int cd9660_rrip_tstamp(ISO_RRIP_TSTAMP
*p
, ISO_RRIP_ANALYZE
*ana
);
83 * POSIX file attribute
86 cd9660_rrip_attr(ISO_RRIP_ATTR
*p
, ISO_RRIP_ANALYZE
*ana
)
88 ana
->inop
->inode
.iso_mode
= isonum_733(p
->mode
);
89 ana
->inop
->inode
.iso_uid
= isonum_733(p
->uid
);
90 ana
->inop
->inode
.iso_gid
= isonum_733(p
->gid
);
91 ana
->inop
->inode
.iso_links
= isonum_733(p
->links
);
92 ana
->fields
&= ~ISO_SUSP_ATTR
;
97 cd9660_rrip_defattr(struct iso_directory_record
*isodir
, ISO_RRIP_ANALYZE
*ana
)
99 /* But this is a required field! */
100 kprintf("RRIP without PX field?\n");
101 cd9660_defattr(isodir
,ana
->inop
,NULL
,ISO_FTYPE_RRIP
);
108 cd9660_rrip_slink(ISO_RRIP_SLINK
*p
, ISO_RRIP_ANALYZE
*ana
)
110 ISO_RRIP_SLINK_COMPONENT
*pcomp
;
111 ISO_RRIP_SLINK_COMPONENT
*pcompe
;
112 int error
, len
, wlen
, cont
;
113 char *outbuf
, *inbuf
, *freebuf
;
115 pcomp
= (ISO_RRIP_SLINK_COMPONENT
*)p
->component
;
116 pcompe
= (ISO_RRIP_SLINK_COMPONENT
*)((char *)p
+ isonum_711(p
->h
.length
));
118 outbuf
= ana
->outbuf
;
123 * Gathering a Symbolic name from each component with path
127 pcomp
= (ISO_RRIP_SLINK_COMPONENT
*)((char *)pcomp
+ ISO_RRIP_SLSIZ
128 + isonum_711(pcomp
->clen
))) {
131 if (len
< ana
->maxlen
) {
141 switch (*pcomp
->cflag
) {
143 case ISO_SUSP_CFLAG_CURRENT
:
144 /* Inserting Current */
148 case ISO_SUSP_CFLAG_PARENT
:
149 /* Inserting Parent */
153 case ISO_SUSP_CFLAG_ROOT
:
154 /* Inserting slash for ROOT */
155 /* start over from beginning(?) */
160 case ISO_SUSP_CFLAG_VOLROOT
:
161 /* Inserting a mount point i.e. "/cdrom" */
165 error
= cache_fullpath(NULL
, &ana
->imp
->im_mountp
->mnt_ncmountpt
, NULL
,
166 &inbuf
, &freebuf
, 0);
169 wlen
= strlen(inbuf
);
172 case ISO_SUSP_CFLAG_HOST
:
173 /* Inserting hostname i.e. "kurt.tools.de" */
175 wlen
= strlen(hostname
);
178 case ISO_SUSP_CFLAG_CONTINUE
:
182 /* Inserting component */
183 wlen
= isonum_711(pcomp
->clen
);
187 kprintf("RRIP with incorrect flags?");
188 wlen
= ana
->maxlen
+ 1;
192 if (len
+ wlen
> ana
->maxlen
)
195 bcopy(inbuf
,outbuf
,wlen
);
199 if (freebuf
!= NULL
) {
200 kfree(freebuf
, M_TEMP
);
204 ana
->outbuf
= outbuf
;
208 if (!isonum_711(p
->flags
)) {
209 ana
->fields
&= ~ISO_SUSP_SLINK
;
210 return ISO_SUSP_SLINK
;
216 kfree(freebuf
, M_TEMP
);
219 ana
->outbuf
-= *ana
->outlen
;
228 cd9660_rrip_altname(ISO_RRIP_ALTNAME
*p
, ISO_RRIP_ANALYZE
*ana
)
239 case ISO_SUSP_CFLAG_CURRENT
:
240 /* Inserting Current */
244 case ISO_SUSP_CFLAG_PARENT
:
245 /* Inserting Parent */
249 case ISO_SUSP_CFLAG_HOST
:
250 /* Inserting hostname i.e. "kurt.tools.de" */
252 wlen
= strlen(hostname
);
255 case ISO_SUSP_CFLAG_CONTINUE
:
259 /* Inserting component */
260 wlen
= isonum_711(p
->h
.length
) - 5;
261 inbuf
= (char *)p
+ 5;
265 kprintf("RRIP with incorrect NM flags?\n");
266 wlen
= ana
->maxlen
+ 1;
270 if ((*ana
->outlen
+= wlen
) > ana
->maxlen
) {
271 /* treat as no name field */
272 ana
->fields
&= ~ISO_SUSP_ALTNAME
;
273 ana
->outbuf
-= *ana
->outlen
- wlen
;
278 bcopy(inbuf
,ana
->outbuf
,wlen
);
282 ana
->fields
&= ~ISO_SUSP_ALTNAME
;
283 return ISO_SUSP_ALTNAME
;
289 cd9660_rrip_defname(struct iso_directory_record
*isodir
, ISO_RRIP_ANALYZE
*ana
)
291 isofntrans(isodir
->name
,isonum_711(isodir
->name_len
),
292 ana
->outbuf
,ana
->outlen
,
293 1,isonum_711(isodir
->flags
)&4, ana
->imp
->joliet_level
,
294 ana
->imp
->im_flags
, ana
->imp
->im_d2l
);
295 switch (*ana
->outbuf
) {
302 /* outlen is 1 already */
303 strcpy(ana
->outbuf
,"..");
309 * Parent or Child Link
312 cd9660_rrip_pclink(ISO_RRIP_CLINK
*p
, ISO_RRIP_ANALYZE
*ana
)
314 *ana
->inump
= isonum_733(p
->dir_loc
) << ana
->imp
->im_bshift
;
315 ana
->fields
&= ~(ISO_SUSP_CLINK
|ISO_SUSP_PLINK
);
316 return *p
->h
.type
== 'C' ? ISO_SUSP_CLINK
: ISO_SUSP_PLINK
;
320 * Relocated directory
323 cd9660_rrip_reldir(ISO_RRIP_RELDIR
*p
, ISO_RRIP_ANALYZE
*ana
)
325 /* special hack to make caller aware of RE field */
328 return ISO_SUSP_RELDIR
|ISO_SUSP_ALTNAME
|ISO_SUSP_CLINK
|ISO_SUSP_PLINK
;
332 cd9660_rrip_tstamp(ISO_RRIP_TSTAMP
*p
, ISO_RRIP_ANALYZE
*ana
)
338 /* Check a format of time stamp (7bytes/17bytes) */
339 if (!(*p
->flags
&ISO_SUSP_TSTAMP_FORM17
)) {
340 if (*p
->flags
&ISO_SUSP_TSTAMP_CREAT
)
343 if (*p
->flags
&ISO_SUSP_TSTAMP_MODIFY
) {
344 cd9660_tstamp_conv7(ptime
,&ana
->inop
->inode
.iso_mtime
,
348 bzero(&ana
->inop
->inode
.iso_mtime
,sizeof(struct timespec
));
350 if (*p
->flags
&ISO_SUSP_TSTAMP_ACCESS
) {
351 cd9660_tstamp_conv7(ptime
,&ana
->inop
->inode
.iso_atime
,
355 ana
->inop
->inode
.iso_atime
= ana
->inop
->inode
.iso_mtime
;
357 if (*p
->flags
&ISO_SUSP_TSTAMP_ATTR
)
358 cd9660_tstamp_conv7(ptime
,&ana
->inop
->inode
.iso_ctime
,
361 ana
->inop
->inode
.iso_ctime
= ana
->inop
->inode
.iso_mtime
;
364 if (*p
->flags
&ISO_SUSP_TSTAMP_CREAT
)
367 if (*p
->flags
&ISO_SUSP_TSTAMP_MODIFY
) {
368 cd9660_tstamp_conv17(ptime
,&ana
->inop
->inode
.iso_mtime
);
371 bzero(&ana
->inop
->inode
.iso_mtime
,sizeof(struct timespec
));
373 if (*p
->flags
&ISO_SUSP_TSTAMP_ACCESS
) {
374 cd9660_tstamp_conv17(ptime
,&ana
->inop
->inode
.iso_atime
);
377 ana
->inop
->inode
.iso_atime
= ana
->inop
->inode
.iso_mtime
;
379 if (*p
->flags
&ISO_SUSP_TSTAMP_ATTR
)
380 cd9660_tstamp_conv17(ptime
,&ana
->inop
->inode
.iso_ctime
);
382 ana
->inop
->inode
.iso_ctime
= ana
->inop
->inode
.iso_mtime
;
385 ana
->fields
&= ~ISO_SUSP_TSTAMP
;
386 return ISO_SUSP_TSTAMP
;
390 cd9660_rrip_deftstamp(struct iso_directory_record
*isodir
, ISO_RRIP_ANALYZE
*ana
)
392 cd9660_deftstamp(isodir
,ana
->inop
,NULL
,ISO_FTYPE_RRIP
);
399 cd9660_rrip_device(ISO_RRIP_DEVICE
*p
, ISO_RRIP_ANALYZE
*ana
)
403 high
= isonum_733(p
->dev_t_high
);
404 low
= isonum_733(p
->dev_t_low
);
407 ana
->inop
->inode
.iso_rdev
= makeudev(umajor(low
), uminor(low
));
409 ana
->inop
->inode
.iso_rdev
= makeudev(high
, uminor(low
));
410 ana
->fields
&= ~ISO_SUSP_DEVICE
;
411 return ISO_SUSP_DEVICE
;
418 cd9660_rrip_idflag(ISO_RRIP_IDFLAG
*p
, ISO_RRIP_ANALYZE
*ana
)
420 ana
->fields
&= isonum_711(p
->flags
)|~0xff; /* don't touch high bits */
421 /* special handling of RE field */
422 if (ana
->fields
&ISO_SUSP_RELDIR
)
423 return cd9660_rrip_reldir(/* XXX */ (ISO_RRIP_RELDIR
*)p
,ana
);
425 return ISO_SUSP_IDFLAG
;
429 * Continuation pointer
432 cd9660_rrip_cont(ISO_RRIP_CONT
*p
, ISO_RRIP_ANALYZE
*ana
)
434 ana
->iso_ce_blk
= isonum_733(p
->location
);
435 ana
->iso_ce_off
= isonum_733(p
->offset
);
436 ana
->iso_ce_len
= isonum_733(p
->length
);
437 return ISO_SUSP_CONT
;
444 cd9660_rrip_stop(ISO_SUSP_HEADER
*p
, ISO_RRIP_ANALYZE
*ana
)
446 return ISO_SUSP_STOP
;
450 * Extension reference
453 cd9660_rrip_extref(ISO_RRIP_EXTREF
*p
, ISO_RRIP_ANALYZE
*ana
)
455 if (isonum_711(p
->len_id
) != 10
456 || bcmp((char *)p
+ 8,"RRIP_1991A",10)
457 || isonum_711(p
->version
) != 1)
459 ana
->fields
&= ~ISO_SUSP_EXTREF
;
460 return ISO_SUSP_EXTREF
;
464 cd9660_rrip_loop(struct iso_directory_record
*isodir
, ISO_RRIP_ANALYZE
*ana
,
468 ISO_SUSP_HEADER
*phead
;
469 ISO_SUSP_HEADER
*pend
;
470 struct buf
*bp
= NULL
;
476 * Note: If name length is odd,
477 * it will be padding 1 byte after the name
479 pwhead
= isodir
->name
+ isonum_711(isodir
->name_len
);
480 if (!(isonum_711(isodir
->name_len
)&1))
482 isochar(isodir
->name
, pwhead
, ana
->imp
->joliet_level
, &c
, NULL
,
483 ana
->imp
->im_flags
, ana
->imp
->im_d2l
);
485 /* If it's not the '.' entry of the root dir obey SP field */
486 if (c
!= 0 || isonum_733(isodir
->extent
) != ana
->imp
->root_extent
)
487 pwhead
+= ana
->imp
->rr_skip
;
489 pwhead
+= ana
->imp
->rr_skip0
;
491 phead
= (ISO_SUSP_HEADER
*)pwhead
;
492 pend
= (ISO_SUSP_HEADER
*)((char *)isodir
+ isonum_711(isodir
->length
));
498 * Note: "pend" should be more than one SUSP header
500 while (pend
>= phead
+ 1) {
501 if (isonum_711(phead
->version
) == 1) {
502 for (ptable
= table
; ptable
->func
; ptable
++) {
503 if (*phead
->type
== *ptable
->type
504 && phead
->type
[1] == ptable
->type
[1]) {
505 result
|= ptable
->func(phead
,ana
);
512 if (result
&ISO_SUSP_STOP
) {
513 result
&= ~ISO_SUSP_STOP
;
516 /* plausibility check */
517 if (isonum_711(phead
->length
) < sizeof(*phead
))
521 * Hopefully this works with newer versions, too
523 phead
= (ISO_SUSP_HEADER
*)((char *)phead
+ isonum_711(phead
->length
));
526 if (ana
->fields
&& ana
->iso_ce_len
) {
527 if (ana
->iso_ce_blk
>= ana
->imp
->volume_space_size
528 || ana
->iso_ce_off
+ ana
->iso_ce_len
> ana
->imp
->logical_block_size
529 || bread(ana
->imp
->im_devvp
,
530 lblktooff(ana
->imp
, ana
->iso_ce_blk
),
531 ana
->imp
->logical_block_size
, &bp
))
532 /* what to do now? */
534 phead
= (ISO_SUSP_HEADER
*)(bp
->b_data
+ ana
->iso_ce_off
);
535 pend
= (ISO_SUSP_HEADER
*) ((char *)phead
+ ana
->iso_ce_len
);
542 * If we don't find the Basic SUSP stuffs, just set default value
543 * (attribute/time stamp)
545 for (ptable
= table
; ptable
->func2
; ptable
++)
546 if (!(ptable
->result
&result
))
547 ptable
->func2(isodir
,ana
);
556 * XXX the casts are bogus but will do for now.
558 #define BC (rrt_func_t *)
559 static RRIP_TABLE rrip_table_analyze
[] = {
560 { "PX", BC cd9660_rrip_attr
, cd9660_rrip_defattr
, ISO_SUSP_ATTR
},
561 { "TF", BC cd9660_rrip_tstamp
, cd9660_rrip_deftstamp
, ISO_SUSP_TSTAMP
},
562 { "PN", BC cd9660_rrip_device
, 0, ISO_SUSP_DEVICE
},
563 { "RR", BC cd9660_rrip_idflag
, 0, ISO_SUSP_IDFLAG
},
564 { "CE", BC cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
565 { "ST", BC cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
570 cd9660_rrip_analyze(struct iso_directory_record
*isodir
, struct iso_node
*inop
,
573 ISO_RRIP_ANALYZE analyze
;
577 analyze
.fields
= ISO_SUSP_ATTR
|ISO_SUSP_TSTAMP
|ISO_SUSP_DEVICE
;
579 return cd9660_rrip_loop(isodir
,&analyze
,rrip_table_analyze
);
583 * Get Alternate Name.
585 static RRIP_TABLE rrip_table_getname
[] = {
586 { "NM", BC cd9660_rrip_altname
, cd9660_rrip_defname
, ISO_SUSP_ALTNAME
},
587 { "CL", BC cd9660_rrip_pclink
, 0, ISO_SUSP_CLINK
|ISO_SUSP_PLINK
},
588 { "PL", BC cd9660_rrip_pclink
, 0, ISO_SUSP_CLINK
|ISO_SUSP_PLINK
},
589 { "RE", BC cd9660_rrip_reldir
, 0, ISO_SUSP_RELDIR
},
590 { "RR", BC cd9660_rrip_idflag
, 0, ISO_SUSP_IDFLAG
},
591 { "CE", BC cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
592 { "ST", BC cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
597 cd9660_rrip_getname(struct iso_directory_record
*isodir
, char *outbuf
,
598 u_short
*outlen
, ino_t
*inump
, struct iso_mnt
*imp
)
600 ISO_RRIP_ANALYZE analyze
;
604 analyze
.outbuf
= outbuf
;
605 analyze
.outlen
= outlen
;
606 analyze
.maxlen
= NAME_MAX
;
607 analyze
.inump
= inump
;
609 analyze
.fields
= ISO_SUSP_ALTNAME
|ISO_SUSP_RELDIR
|ISO_SUSP_CLINK
|ISO_SUSP_PLINK
;
612 isochar(isodir
->name
, isodir
->name
+ isonum_711(isodir
->name_len
),
613 imp
->joliet_level
, &c
, NULL
, imp
->im_flags
, imp
->im_d2l
);
614 tab
= rrip_table_getname
;
615 if (c
== 0 || c
== 1) {
616 cd9660_rrip_defname(isodir
,&analyze
);
618 analyze
.fields
&= ~ISO_SUSP_ALTNAME
;
622 return cd9660_rrip_loop(isodir
,&analyze
,tab
);
628 static RRIP_TABLE rrip_table_getsymname
[] = {
629 { "SL", BC cd9660_rrip_slink
, 0, ISO_SUSP_SLINK
},
630 { "RR", BC cd9660_rrip_idflag
, 0, ISO_SUSP_IDFLAG
},
631 { "CE", BC cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
632 { "ST", BC cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
637 cd9660_rrip_getsymname(struct iso_directory_record
*isodir
, char *outbuf
,
638 u_short
*outlen
, struct iso_mnt
*imp
)
640 ISO_RRIP_ANALYZE analyze
;
642 analyze
.outbuf
= outbuf
;
643 analyze
.outlen
= outlen
;
645 analyze
.maxlen
= MAXPATHLEN
;
646 analyze
.cont
= 1; /* don't start with a slash */
648 analyze
.fields
= ISO_SUSP_SLINK
;
650 return (cd9660_rrip_loop(isodir
,&analyze
,rrip_table_getsymname
)&ISO_SUSP_SLINK
);
653 static RRIP_TABLE rrip_table_extref
[] = {
654 { "ER", BC cd9660_rrip_extref
, 0, ISO_SUSP_EXTREF
},
655 { "CE", BC cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
656 { "ST", BC cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
661 * Check for Rock Ridge Extension and return offset of its fields.
662 * Note: We insist on the ER field.
665 cd9660_rrip_offset(struct iso_directory_record
*isodir
, struct iso_mnt
*imp
)
668 ISO_RRIP_ANALYZE analyze
;
671 p
= (ISO_RRIP_OFFSET
*)(isodir
->name
+ 1);
672 if (bcmp(p
,"SP\7\1\276\357",6)) {
673 /* Maybe, it's a CDROM XA disc? */
675 p
= (ISO_RRIP_OFFSET
*)((char *)p
+ 15);
676 if (bcmp(p
,"SP\7\1\276\357",6))
681 analyze
.fields
= ISO_SUSP_EXTREF
;
682 if (!(cd9660_rrip_loop(isodir
,&analyze
,rrip_table_extref
)&ISO_SUSP_EXTREF
))
685 return isonum_711(p
->skip
);