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>
46 #include "cd9660_node.h"
47 #include "cd9660_rrip.h"
52 typedef int rrt_func_t(void *, ISO_RRIP_ANALYZE
*ana
);
57 void (*func2
)(struct iso_directory_record
*isodir
, ISO_RRIP_ANALYZE
*ana
);
61 static int cd9660_rrip_altname(ISO_RRIP_ALTNAME
*p
, ISO_RRIP_ANALYZE
*ana
);
62 static int cd9660_rrip_attr(ISO_RRIP_ATTR
*p
, ISO_RRIP_ANALYZE
*ana
);
63 static int cd9660_rrip_cont(ISO_RRIP_CONT
*p
, ISO_RRIP_ANALYZE
*ana
);
64 static void cd9660_rrip_defattr(struct iso_directory_record
*isodir
,
65 ISO_RRIP_ANALYZE
*ana
);
66 static void cd9660_rrip_defname(struct iso_directory_record
*isodir
,
67 ISO_RRIP_ANALYZE
*ana
);
68 static void cd9660_rrip_deftstamp(struct iso_directory_record
*isodir
,
69 ISO_RRIP_ANALYZE
*ana
);
70 static int cd9660_rrip_device(ISO_RRIP_DEVICE
*p
, ISO_RRIP_ANALYZE
*ana
);
71 static int cd9660_rrip_extref(ISO_RRIP_EXTREF
*p
, ISO_RRIP_ANALYZE
*ana
);
72 static int cd9660_rrip_idflag(ISO_RRIP_IDFLAG
*p
, ISO_RRIP_ANALYZE
*ana
);
73 static int cd9660_rrip_loop(struct iso_directory_record
*isodir
,
74 ISO_RRIP_ANALYZE
*ana
, RRIP_TABLE
*table
);
75 static int cd9660_rrip_pclink(ISO_RRIP_CLINK
*p
, ISO_RRIP_ANALYZE
*ana
);
76 static int cd9660_rrip_reldir(ISO_RRIP_RELDIR
*p
, ISO_RRIP_ANALYZE
*ana
);
77 static int cd9660_rrip_slink(ISO_RRIP_SLINK
*p
, ISO_RRIP_ANALYZE
*ana
);
78 static int cd9660_rrip_stop(ISO_SUSP_HEADER
*p
, ISO_RRIP_ANALYZE
*ana
);
79 static int cd9660_rrip_tstamp(ISO_RRIP_TSTAMP
*p
, ISO_RRIP_ANALYZE
*ana
);
82 * POSIX file attribute
85 cd9660_rrip_attr(ISO_RRIP_ATTR
*p
, ISO_RRIP_ANALYZE
*ana
)
87 ana
->inop
->inode
.iso_mode
= isonum_733(p
->mode
);
88 ana
->inop
->inode
.iso_uid
= isonum_733(p
->uid
);
89 ana
->inop
->inode
.iso_gid
= isonum_733(p
->gid
);
90 ana
->inop
->inode
.iso_links
= isonum_733(p
->links
);
91 ana
->fields
&= ~ISO_SUSP_ATTR
;
96 cd9660_rrip_defattr(struct iso_directory_record
*isodir
, ISO_RRIP_ANALYZE
*ana
)
98 /* But this is a required field! */
99 kprintf("RRIP without PX field?\n");
100 cd9660_defattr(isodir
,ana
->inop
,NULL
,ISO_FTYPE_RRIP
);
107 cd9660_rrip_slink(ISO_RRIP_SLINK
*p
, ISO_RRIP_ANALYZE
*ana
)
109 ISO_RRIP_SLINK_COMPONENT
*pcomp
;
110 ISO_RRIP_SLINK_COMPONENT
*pcompe
;
111 int error
, len
, wlen
, cont
;
112 char *outbuf
, *inbuf
, *freebuf
;
114 pcomp
= (ISO_RRIP_SLINK_COMPONENT
*)p
->component
;
115 pcompe
= (ISO_RRIP_SLINK_COMPONENT
*)((char *)p
+ isonum_711(p
->h
.length
));
117 outbuf
= ana
->outbuf
;
122 * Gathering a Symbolic name from each component with path
126 pcomp
= (ISO_RRIP_SLINK_COMPONENT
*)((char *)pcomp
+ ISO_RRIP_SLSIZ
127 + isonum_711(pcomp
->clen
))) {
130 if (len
< ana
->maxlen
) {
140 switch (*pcomp
->cflag
) {
142 case ISO_SUSP_CFLAG_CURRENT
:
143 /* Inserting Current */
147 case ISO_SUSP_CFLAG_PARENT
:
148 /* Inserting Parent */
152 case ISO_SUSP_CFLAG_ROOT
:
153 /* Inserting slash for ROOT */
154 /* start over from beginning(?) */
159 case ISO_SUSP_CFLAG_VOLROOT
:
160 /* Inserting a mount point i.e. "/cdrom" */
164 error
= cache_fullpath(NULL
, &ana
->imp
->im_mountp
->mnt_ncmountpt
, NULL
,
165 &inbuf
, &freebuf
, 0);
168 wlen
= strlen(inbuf
);
171 case ISO_SUSP_CFLAG_HOST
:
172 /* Inserting hostname i.e. "kurt.tools.de" */
174 wlen
= strlen(hostname
);
177 case ISO_SUSP_CFLAG_CONTINUE
:
181 /* Inserting component */
182 wlen
= isonum_711(pcomp
->clen
);
186 kprintf("RRIP with incorrect flags?");
187 wlen
= ana
->maxlen
+ 1;
191 if (len
+ wlen
> ana
->maxlen
)
194 bcopy(inbuf
,outbuf
,wlen
);
198 if (freebuf
!= NULL
) {
199 kfree(freebuf
, M_TEMP
);
203 ana
->outbuf
= outbuf
;
207 if (!isonum_711(p
->flags
)) {
208 ana
->fields
&= ~ISO_SUSP_SLINK
;
209 return ISO_SUSP_SLINK
;
215 kfree(freebuf
, M_TEMP
);
218 ana
->outbuf
-= *ana
->outlen
;
227 cd9660_rrip_altname(ISO_RRIP_ALTNAME
*p
, ISO_RRIP_ANALYZE
*ana
)
238 case ISO_SUSP_CFLAG_CURRENT
:
239 /* Inserting Current */
243 case ISO_SUSP_CFLAG_PARENT
:
244 /* Inserting Parent */
248 case ISO_SUSP_CFLAG_HOST
:
249 /* Inserting hostname i.e. "kurt.tools.de" */
251 wlen
= strlen(hostname
);
254 case ISO_SUSP_CFLAG_CONTINUE
:
258 /* Inserting component */
259 wlen
= isonum_711(p
->h
.length
) - 5;
260 inbuf
= (char *)p
+ 5;
264 kprintf("RRIP with incorrect NM flags?\n");
265 wlen
= ana
->maxlen
+ 1;
269 if ((*ana
->outlen
+= wlen
) > ana
->maxlen
) {
270 /* treat as no name field */
271 ana
->fields
&= ~ISO_SUSP_ALTNAME
;
272 ana
->outbuf
-= *ana
->outlen
- wlen
;
277 bcopy(inbuf
,ana
->outbuf
,wlen
);
281 ana
->fields
&= ~ISO_SUSP_ALTNAME
;
282 return ISO_SUSP_ALTNAME
;
288 cd9660_rrip_defname(struct iso_directory_record
*isodir
, ISO_RRIP_ANALYZE
*ana
)
290 isofntrans(isodir
->name
,isonum_711(isodir
->name_len
),
291 ana
->outbuf
,ana
->outlen
,
292 1,isonum_711(isodir
->flags
)&4, ana
->imp
->joliet_level
,
293 ana
->imp
->im_flags
, ana
->imp
->im_d2l
);
294 switch (*ana
->outbuf
) {
301 /* outlen is 1 already */
302 strcpy(ana
->outbuf
,"..");
308 * Parent or Child Link
311 cd9660_rrip_pclink(ISO_RRIP_CLINK
*p
, ISO_RRIP_ANALYZE
*ana
)
313 *ana
->inump
= isonum_733(p
->dir_loc
) << ana
->imp
->im_bshift
;
314 ana
->fields
&= ~(ISO_SUSP_CLINK
|ISO_SUSP_PLINK
);
315 return *p
->h
.type
== 'C' ? ISO_SUSP_CLINK
: ISO_SUSP_PLINK
;
319 * Relocated directory
322 cd9660_rrip_reldir(ISO_RRIP_RELDIR
*p
, ISO_RRIP_ANALYZE
*ana
)
324 /* special hack to make caller aware of RE field */
327 return ISO_SUSP_RELDIR
|ISO_SUSP_ALTNAME
|ISO_SUSP_CLINK
|ISO_SUSP_PLINK
;
331 cd9660_rrip_tstamp(ISO_RRIP_TSTAMP
*p
, ISO_RRIP_ANALYZE
*ana
)
337 /* Check a format of time stamp (7bytes/17bytes) */
338 if (!(*p
->flags
&ISO_SUSP_TSTAMP_FORM17
)) {
339 if (*p
->flags
&ISO_SUSP_TSTAMP_CREAT
)
342 if (*p
->flags
&ISO_SUSP_TSTAMP_MODIFY
) {
343 cd9660_tstamp_conv7(ptime
,&ana
->inop
->inode
.iso_mtime
,
347 bzero(&ana
->inop
->inode
.iso_mtime
,sizeof(struct timespec
));
349 if (*p
->flags
&ISO_SUSP_TSTAMP_ACCESS
) {
350 cd9660_tstamp_conv7(ptime
,&ana
->inop
->inode
.iso_atime
,
354 ana
->inop
->inode
.iso_atime
= ana
->inop
->inode
.iso_mtime
;
356 if (*p
->flags
&ISO_SUSP_TSTAMP_ATTR
)
357 cd9660_tstamp_conv7(ptime
,&ana
->inop
->inode
.iso_ctime
,
360 ana
->inop
->inode
.iso_ctime
= ana
->inop
->inode
.iso_mtime
;
363 if (*p
->flags
&ISO_SUSP_TSTAMP_CREAT
)
366 if (*p
->flags
&ISO_SUSP_TSTAMP_MODIFY
) {
367 cd9660_tstamp_conv17(ptime
,&ana
->inop
->inode
.iso_mtime
);
370 bzero(&ana
->inop
->inode
.iso_mtime
,sizeof(struct timespec
));
372 if (*p
->flags
&ISO_SUSP_TSTAMP_ACCESS
) {
373 cd9660_tstamp_conv17(ptime
,&ana
->inop
->inode
.iso_atime
);
376 ana
->inop
->inode
.iso_atime
= ana
->inop
->inode
.iso_mtime
;
378 if (*p
->flags
&ISO_SUSP_TSTAMP_ATTR
)
379 cd9660_tstamp_conv17(ptime
,&ana
->inop
->inode
.iso_ctime
);
381 ana
->inop
->inode
.iso_ctime
= ana
->inop
->inode
.iso_mtime
;
384 ana
->fields
&= ~ISO_SUSP_TSTAMP
;
385 return ISO_SUSP_TSTAMP
;
389 cd9660_rrip_deftstamp(struct iso_directory_record
*isodir
, ISO_RRIP_ANALYZE
*ana
)
391 cd9660_deftstamp(isodir
,ana
->inop
,NULL
,ISO_FTYPE_RRIP
);
398 cd9660_rrip_device(ISO_RRIP_DEVICE
*p
, ISO_RRIP_ANALYZE
*ana
)
402 high
= isonum_733(p
->dev_t_high
);
403 low
= isonum_733(p
->dev_t_low
);
406 ana
->inop
->inode
.iso_rdev
= makeudev(umajor(low
), uminor(low
));
408 ana
->inop
->inode
.iso_rdev
= makeudev(high
, uminor(low
));
409 ana
->fields
&= ~ISO_SUSP_DEVICE
;
410 return ISO_SUSP_DEVICE
;
417 cd9660_rrip_idflag(ISO_RRIP_IDFLAG
*p
, ISO_RRIP_ANALYZE
*ana
)
419 ana
->fields
&= isonum_711(p
->flags
)|~0xff; /* don't touch high bits */
420 /* special handling of RE field */
421 if (ana
->fields
&ISO_SUSP_RELDIR
)
422 return cd9660_rrip_reldir(/* XXX */ (ISO_RRIP_RELDIR
*)p
,ana
);
424 return ISO_SUSP_IDFLAG
;
428 * Continuation pointer
431 cd9660_rrip_cont(ISO_RRIP_CONT
*p
, ISO_RRIP_ANALYZE
*ana
)
433 ana
->iso_ce_blk
= isonum_733(p
->location
);
434 ana
->iso_ce_off
= isonum_733(p
->offset
);
435 ana
->iso_ce_len
= isonum_733(p
->length
);
436 return ISO_SUSP_CONT
;
443 cd9660_rrip_stop(ISO_SUSP_HEADER
*p
, ISO_RRIP_ANALYZE
*ana
)
445 return ISO_SUSP_STOP
;
449 * Extension reference
452 cd9660_rrip_extref(ISO_RRIP_EXTREF
*p
, ISO_RRIP_ANALYZE
*ana
)
454 if (isonum_711(p
->len_id
) != 10
455 || bcmp((char *)p
+ 8,"RRIP_1991A",10)
456 || isonum_711(p
->version
) != 1)
458 ana
->fields
&= ~ISO_SUSP_EXTREF
;
459 return ISO_SUSP_EXTREF
;
463 cd9660_rrip_loop(struct iso_directory_record
*isodir
, ISO_RRIP_ANALYZE
*ana
,
467 ISO_SUSP_HEADER
*phead
;
468 ISO_SUSP_HEADER
*pend
;
469 struct buf
*bp
= NULL
;
475 * Note: If name length is odd,
476 * it will be padding 1 byte after the name
478 pwhead
= isodir
->name
+ isonum_711(isodir
->name_len
);
479 if (!(isonum_711(isodir
->name_len
)&1))
481 isochar(isodir
->name
, pwhead
, ana
->imp
->joliet_level
, &c
, NULL
,
482 ana
->imp
->im_flags
, ana
->imp
->im_d2l
);
484 /* If it's not the '.' entry of the root dir obey SP field */
485 if (c
!= 0 || isonum_733(isodir
->extent
) != ana
->imp
->root_extent
)
486 pwhead
+= ana
->imp
->rr_skip
;
488 pwhead
+= ana
->imp
->rr_skip0
;
490 phead
= (ISO_SUSP_HEADER
*)pwhead
;
491 pend
= (ISO_SUSP_HEADER
*)((char *)isodir
+ isonum_711(isodir
->length
));
497 * Note: "pend" should be more than one SUSP header
499 while (pend
>= phead
+ 1) {
500 if (isonum_711(phead
->version
) == 1) {
501 for (ptable
= table
; ptable
->func
; ptable
++) {
502 if (*phead
->type
== *ptable
->type
503 && phead
->type
[1] == ptable
->type
[1]) {
504 result
|= ptable
->func(phead
,ana
);
511 if (result
&ISO_SUSP_STOP
) {
512 result
&= ~ISO_SUSP_STOP
;
515 /* plausibility check */
516 if (isonum_711(phead
->length
) < sizeof(*phead
))
520 * Hopefully this works with newer versions, too
522 phead
= (ISO_SUSP_HEADER
*)((char *)phead
+ isonum_711(phead
->length
));
525 if (ana
->fields
&& ana
->iso_ce_len
) {
526 if (ana
->iso_ce_blk
>= ana
->imp
->volume_space_size
527 || ana
->iso_ce_off
+ ana
->iso_ce_len
> ana
->imp
->logical_block_size
528 || bread(ana
->imp
->im_devvp
,
529 lblktooff(ana
->imp
, ana
->iso_ce_blk
),
530 ana
->imp
->logical_block_size
, &bp
))
531 /* what to do now? */
533 phead
= (ISO_SUSP_HEADER
*)(bp
->b_data
+ ana
->iso_ce_off
);
534 pend
= (ISO_SUSP_HEADER
*) ((char *)phead
+ ana
->iso_ce_len
);
541 * If we don't find the Basic SUSP stuffs, just set default value
542 * (attribute/time stamp)
544 for (ptable
= table
; ptable
->func2
; ptable
++)
545 if (!(ptable
->result
&result
))
546 ptable
->func2(isodir
,ana
);
555 * XXX the casts are bogus but will do for now.
557 #define BC (rrt_func_t *)
558 static RRIP_TABLE rrip_table_analyze
[] = {
559 { "PX", BC cd9660_rrip_attr
, cd9660_rrip_defattr
, ISO_SUSP_ATTR
},
560 { "TF", BC cd9660_rrip_tstamp
, cd9660_rrip_deftstamp
, ISO_SUSP_TSTAMP
},
561 { "PN", BC cd9660_rrip_device
, 0, ISO_SUSP_DEVICE
},
562 { "RR", BC cd9660_rrip_idflag
, 0, ISO_SUSP_IDFLAG
},
563 { "CE", BC cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
564 { "ST", BC cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
569 cd9660_rrip_analyze(struct iso_directory_record
*isodir
, struct iso_node
*inop
,
572 ISO_RRIP_ANALYZE analyze
;
576 analyze
.fields
= ISO_SUSP_ATTR
|ISO_SUSP_TSTAMP
|ISO_SUSP_DEVICE
;
578 return cd9660_rrip_loop(isodir
,&analyze
,rrip_table_analyze
);
582 * Get Alternate Name.
584 static RRIP_TABLE rrip_table_getname
[] = {
585 { "NM", BC cd9660_rrip_altname
, cd9660_rrip_defname
, ISO_SUSP_ALTNAME
},
586 { "CL", BC cd9660_rrip_pclink
, 0, ISO_SUSP_CLINK
|ISO_SUSP_PLINK
},
587 { "PL", BC cd9660_rrip_pclink
, 0, ISO_SUSP_CLINK
|ISO_SUSP_PLINK
},
588 { "RE", BC cd9660_rrip_reldir
, 0, ISO_SUSP_RELDIR
},
589 { "RR", BC cd9660_rrip_idflag
, 0, ISO_SUSP_IDFLAG
},
590 { "CE", BC cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
591 { "ST", BC cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
596 cd9660_rrip_getname(struct iso_directory_record
*isodir
, char *outbuf
,
597 u_short
*outlen
, ino_t
*inump
, struct iso_mnt
*imp
)
599 ISO_RRIP_ANALYZE analyze
;
603 analyze
.outbuf
= outbuf
;
604 analyze
.outlen
= outlen
;
605 analyze
.maxlen
= NAME_MAX
;
606 analyze
.inump
= inump
;
608 analyze
.fields
= ISO_SUSP_ALTNAME
|ISO_SUSP_RELDIR
|ISO_SUSP_CLINK
|ISO_SUSP_PLINK
;
611 isochar(isodir
->name
, isodir
->name
+ isonum_711(isodir
->name_len
),
612 imp
->joliet_level
, &c
, NULL
, imp
->im_flags
, imp
->im_d2l
);
613 tab
= rrip_table_getname
;
614 if (c
== 0 || c
== 1) {
615 cd9660_rrip_defname(isodir
,&analyze
);
617 analyze
.fields
&= ~ISO_SUSP_ALTNAME
;
621 return cd9660_rrip_loop(isodir
,&analyze
,tab
);
627 static RRIP_TABLE rrip_table_getsymname
[] = {
628 { "SL", BC cd9660_rrip_slink
, 0, ISO_SUSP_SLINK
},
629 { "RR", BC cd9660_rrip_idflag
, 0, ISO_SUSP_IDFLAG
},
630 { "CE", BC cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
631 { "ST", BC cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
636 cd9660_rrip_getsymname(struct iso_directory_record
*isodir
, char *outbuf
,
637 u_short
*outlen
, struct iso_mnt
*imp
)
639 ISO_RRIP_ANALYZE analyze
;
641 analyze
.outbuf
= outbuf
;
642 analyze
.outlen
= outlen
;
644 analyze
.maxlen
= MAXPATHLEN
;
645 analyze
.cont
= 1; /* don't start with a slash */
647 analyze
.fields
= ISO_SUSP_SLINK
;
649 return (cd9660_rrip_loop(isodir
,&analyze
,rrip_table_getsymname
)&ISO_SUSP_SLINK
);
652 static RRIP_TABLE rrip_table_extref
[] = {
653 { "ER", BC cd9660_rrip_extref
, 0, ISO_SUSP_EXTREF
},
654 { "CE", BC cd9660_rrip_cont
, 0, ISO_SUSP_CONT
},
655 { "ST", BC cd9660_rrip_stop
, 0, ISO_SUSP_STOP
},
660 * Check for Rock Ridge Extension and return offset of its fields.
661 * Note: We insist on the ER field.
664 cd9660_rrip_offset(struct iso_directory_record
*isodir
, struct iso_mnt
*imp
)
667 ISO_RRIP_ANALYZE analyze
;
670 p
= (ISO_RRIP_OFFSET
*)(isodir
->name
+ 1);
671 if (bcmp(p
,"SP\7\1\276\357",6)) {
672 /* Maybe, it's a CDROM XA disc? */
674 p
= (ISO_RRIP_OFFSET
*)((char *)p
+ 15);
675 if (bcmp(p
,"SP\7\1\276\357",6))
680 analyze
.fields
= ISO_SUSP_EXTREF
;
681 if (!(cd9660_rrip_loop(isodir
,&analyze
,rrip_table_extref
)&ISO_SUSP_EXTREF
))
684 return isonum_711(p
->skip
);