cd9660_rrip.c revision 47028
1/*-
2 * Copyright (c) 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
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).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *	@(#)cd9660_rrip.c	8.6 (Berkeley) 12/5/94
39 * $Id: cd9660_rrip.c,v 1.14 1999/04/18 10:58:01 dcs Exp $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/buf.h>
45#include <sys/vnode.h>
46#include <sys/mount.h>
47#include <sys/kernel.h>
48
49#include <isofs/cd9660/iso.h>
50#include <isofs/cd9660/cd9660_node.h>
51#include <isofs/cd9660/cd9660_rrip.h>
52#include <isofs/cd9660/iso_rrip.h>
53
54typedef int	rrt_func_t __P((void *, ISO_RRIP_ANALYZE *ana));
55
56typedef struct {
57	char type[2];
58	rrt_func_t *func;
59	void (*func2) __P((struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana));
60	int result;
61} RRIP_TABLE;
62
63static int	cd9660_rrip_altname __P((ISO_RRIP_ALTNAME *p,
64					 ISO_RRIP_ANALYZE *ana));
65static int	cd9660_rrip_attr __P((ISO_RRIP_ATTR *p, ISO_RRIP_ANALYZE *ana));
66static int	cd9660_rrip_cont __P((ISO_RRIP_CONT *p, ISO_RRIP_ANALYZE *ana));
67static void	cd9660_rrip_defattr __P((struct iso_directory_record *isodir,
68					 ISO_RRIP_ANALYZE *ana));
69static void	cd9660_rrip_defname __P((struct iso_directory_record *isodir,
70					 ISO_RRIP_ANALYZE *ana));
71static void	cd9660_rrip_deftstamp __P((struct iso_directory_record *isodir,
72					   ISO_RRIP_ANALYZE *ana));
73static int	cd9660_rrip_device __P((ISO_RRIP_DEVICE *p,
74					ISO_RRIP_ANALYZE *ana));
75static int	cd9660_rrip_extref __P((ISO_RRIP_EXTREF *p,
76					ISO_RRIP_ANALYZE *ana));
77static int	cd9660_rrip_idflag __P((ISO_RRIP_IDFLAG *p,
78					ISO_RRIP_ANALYZE *ana));
79static int	cd9660_rrip_loop __P((struct iso_directory_record *isodir,
80				      ISO_RRIP_ANALYZE *ana,
81				      RRIP_TABLE *table));
82static int	cd9660_rrip_pclink __P((ISO_RRIP_CLINK *p,
83					ISO_RRIP_ANALYZE *ana));
84static int	cd9660_rrip_reldir __P((ISO_RRIP_RELDIR *p,
85					ISO_RRIP_ANALYZE *ana));
86static int	cd9660_rrip_slink __P((ISO_RRIP_SLINK *p,
87				       ISO_RRIP_ANALYZE *ana));
88static int	cd9660_rrip_stop __P((ISO_SUSP_HEADER *p,
89				      ISO_RRIP_ANALYZE *ana));
90static int	cd9660_rrip_tstamp __P((ISO_RRIP_TSTAMP *p,
91					ISO_RRIP_ANALYZE *ana));
92
93/*
94 * POSIX file attribute
95 */
96static int
97cd9660_rrip_attr(p,ana)
98	ISO_RRIP_ATTR *p;
99	ISO_RRIP_ANALYZE *ana;
100{
101	ana->inop->inode.iso_mode = isonum_733(p->mode);
102	ana->inop->inode.iso_uid = isonum_733(p->uid);
103	ana->inop->inode.iso_gid = isonum_733(p->gid);
104	ana->inop->inode.iso_links = isonum_733(p->links);
105	ana->fields &= ~ISO_SUSP_ATTR;
106	return ISO_SUSP_ATTR;
107}
108
109static void
110cd9660_rrip_defattr(isodir,ana)
111	struct iso_directory_record *isodir;
112	ISO_RRIP_ANALYZE *ana;
113{
114	/* But this is a required field! */
115	printf("RRIP without PX field?\n");
116	cd9660_defattr(isodir,ana->inop,NULL,ISO_FTYPE_RRIP);
117}
118
119/*
120 * Symbolic Links
121 */
122static int
123cd9660_rrip_slink(p,ana)
124	ISO_RRIP_SLINK	*p;
125	ISO_RRIP_ANALYZE *ana;
126{
127	register ISO_RRIP_SLINK_COMPONENT *pcomp;
128	register ISO_RRIP_SLINK_COMPONENT *pcompe;
129	int len, wlen, cont;
130	char *outbuf, *inbuf;
131
132	pcomp = (ISO_RRIP_SLINK_COMPONENT *)p->component;
133	pcompe = (ISO_RRIP_SLINK_COMPONENT *)((char *)p + isonum_711(p->h.length));
134	len = *ana->outlen;
135	outbuf = ana->outbuf;
136	cont = ana->cont;
137
138	/*
139	 * Gathering a Symbolic name from each component with path
140	 */
141	for (;
142	     pcomp < pcompe;
143	     pcomp = (ISO_RRIP_SLINK_COMPONENT *)((char *)pcomp + ISO_RRIP_SLSIZ
144						  + isonum_711(pcomp->clen))) {
145
146		if (!cont) {
147			if (len < ana->maxlen) {
148				len++;
149				*outbuf++ = '/';
150			}
151		}
152		cont = 0;
153
154		inbuf = "..";
155		wlen = 0;
156
157		switch (*pcomp->cflag) {
158
159		case ISO_SUSP_CFLAG_CURRENT:
160			/* Inserting Current */
161			wlen = 1;
162			break;
163
164		case ISO_SUSP_CFLAG_PARENT:
165			/* Inserting Parent */
166			wlen = 2;
167			break;
168
169		case ISO_SUSP_CFLAG_ROOT:
170			/* Inserting slash for ROOT */
171			/* start over from beginning(?) */
172			outbuf -= len;
173			len = 0;
174			break;
175
176		case ISO_SUSP_CFLAG_VOLROOT:
177			/* Inserting a mount point i.e. "/cdrom" */
178			/* same as above */
179			outbuf -= len;
180			len = 0;
181			inbuf = ana->imp->im_mountp->mnt_stat.f_mntonname;
182			wlen = strlen(inbuf);
183			break;
184
185		case ISO_SUSP_CFLAG_HOST:
186			/* Inserting hostname i.e. "kurt.tools.de" */
187			inbuf = hostname;
188			wlen = strlen(hostname);
189			break;
190
191		case ISO_SUSP_CFLAG_CONTINUE:
192			cont = 1;
193			/* fall thru */
194		case 0:
195			/* Inserting component */
196			wlen = isonum_711(pcomp->clen);
197			inbuf = pcomp->name;
198			break;
199		default:
200			printf("RRIP with incorrect flags?");
201			wlen = ana->maxlen + 1;
202			break;
203		}
204
205		if (len + wlen > ana->maxlen) {
206			/* indicate error to caller */
207			ana->cont = 1;
208			ana->fields = 0;
209			ana->outbuf -= *ana->outlen;
210			*ana->outlen = 0;
211			return 0;
212		}
213
214		bcopy(inbuf,outbuf,wlen);
215		outbuf += wlen;
216		len += wlen;
217
218	}
219	ana->outbuf = outbuf;
220	*ana->outlen = len;
221	ana->cont = cont;
222
223	if (!isonum_711(p->flags)) {
224		ana->fields &= ~ISO_SUSP_SLINK;
225		return ISO_SUSP_SLINK;
226	}
227	return 0;
228}
229
230/*
231 * Alternate name
232 */
233static int
234cd9660_rrip_altname(p,ana)
235	ISO_RRIP_ALTNAME *p;
236	ISO_RRIP_ANALYZE *ana;
237{
238	char *inbuf;
239	int wlen;
240	int cont;
241
242	inbuf = "..";
243	wlen = 0;
244	cont = 0;
245
246	switch (*p->flags) {
247	case ISO_SUSP_CFLAG_CURRENT:
248		/* Inserting Current */
249		wlen = 1;
250		break;
251
252	case ISO_SUSP_CFLAG_PARENT:
253		/* Inserting Parent */
254		wlen = 2;
255		break;
256
257	case ISO_SUSP_CFLAG_HOST:
258		/* Inserting hostname i.e. "kurt.tools.de" */
259		inbuf = hostname;
260		wlen = strlen(hostname);
261		break;
262
263	case ISO_SUSP_CFLAG_CONTINUE:
264		cont = 1;
265		/* fall thru */
266	case 0:
267		/* Inserting component */
268		wlen = isonum_711(p->h.length) - 5;
269		inbuf = (char *)p + 5;
270		break;
271
272	default:
273		printf("RRIP with incorrect NM flags?\n");
274		wlen = ana->maxlen + 1;
275		break;
276	}
277
278	if ((*ana->outlen += wlen) > ana->maxlen) {
279		/* treat as no name field */
280		ana->fields &= ~ISO_SUSP_ALTNAME;
281		ana->outbuf -= *ana->outlen - wlen;
282		*ana->outlen = 0;
283		return 0;
284	}
285
286	bcopy(inbuf,ana->outbuf,wlen);
287	ana->outbuf += wlen;
288
289	if (!cont) {
290		ana->fields &= ~ISO_SUSP_ALTNAME;
291		return ISO_SUSP_ALTNAME;
292	}
293	return 0;
294}
295
296static void
297cd9660_rrip_defname(isodir,ana)
298	struct iso_directory_record *isodir;
299	ISO_RRIP_ANALYZE *ana;
300{
301	isofntrans(isodir->name,isonum_711(isodir->name_len),
302		   ana->outbuf,ana->outlen,
303		   1,isonum_711(isodir->flags)&4, ana->imp->joliet_level);
304	switch (*ana->outbuf) {
305	default:
306		break;
307	case 1:
308		*ana->outlen = 2;
309		/* FALL THROUGH */
310	case 0:
311		/* outlen is 1 already */
312		strcpy(ana->outbuf,"..");
313		break;
314	}
315}
316
317/*
318 * Parent or Child Link
319 */
320static int
321cd9660_rrip_pclink(p,ana)
322	ISO_RRIP_CLINK	*p;
323	ISO_RRIP_ANALYZE *ana;
324{
325	*ana->inump = isonum_733(p->dir_loc) << ana->imp->im_bshift;
326	ana->fields &= ~(ISO_SUSP_CLINK|ISO_SUSP_PLINK);
327	return *p->h.type == 'C' ? ISO_SUSP_CLINK : ISO_SUSP_PLINK;
328}
329
330/*
331 * Relocated directory
332 */
333static int
334cd9660_rrip_reldir(p,ana)
335	ISO_RRIP_RELDIR	 *p;
336	ISO_RRIP_ANALYZE *ana;
337{
338	/* special hack to make caller aware of RE field */
339	*ana->outlen = 0;
340	ana->fields = 0;
341	return ISO_SUSP_RELDIR|ISO_SUSP_ALTNAME|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
342}
343
344static int
345cd9660_rrip_tstamp(p,ana)
346	ISO_RRIP_TSTAMP *p;
347	ISO_RRIP_ANALYZE *ana;
348{
349	u_char *ptime;
350
351	ptime = p->time;
352
353	/* Check a format of time stamp (7bytes/17bytes) */
354	if (!(*p->flags&ISO_SUSP_TSTAMP_FORM17)) {
355		if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
356			ptime += 7;
357
358		if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
359			cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_mtime,
360					    ISO_FTYPE_RRIP);
361			ptime += 7;
362		} else
363			bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec));
364
365		if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
366			cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_atime,
367					    ISO_FTYPE_RRIP);
368			ptime += 7;
369		} else
370			ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
371
372		if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
373			cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_ctime,
374					    ISO_FTYPE_RRIP);
375		else
376			ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
377
378	} else {
379		if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
380			ptime += 17;
381
382		if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
383			cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_mtime);
384			ptime += 17;
385		} else
386			bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec));
387
388		if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
389			cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_atime);
390			ptime += 17;
391		} else
392			ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
393
394		if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
395			cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_ctime);
396		else
397			ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
398
399	}
400	ana->fields &= ~ISO_SUSP_TSTAMP;
401	return ISO_SUSP_TSTAMP;
402}
403
404static void
405cd9660_rrip_deftstamp(isodir,ana)
406	struct iso_directory_record  *isodir;
407	ISO_RRIP_ANALYZE *ana;
408{
409	cd9660_deftstamp(isodir,ana->inop,NULL,ISO_FTYPE_RRIP);
410}
411
412/*
413 * POSIX device modes
414 */
415static int
416cd9660_rrip_device(p,ana)
417	ISO_RRIP_DEVICE *p;
418	ISO_RRIP_ANALYZE *ana;
419{
420	u_int high, low;
421
422	high = isonum_733(p->dev_t_high);
423	low  = isonum_733(p->dev_t_low);
424
425	if (high == 0)
426		ana->inop->inode.iso_rdev = umakedev(umajor(low), uminor(low));
427	else
428		ana->inop->inode.iso_rdev = umakedev(high, uminor(low));
429	ana->fields &= ~ISO_SUSP_DEVICE;
430	return ISO_SUSP_DEVICE;
431}
432
433/*
434 * Flag indicating
435 */
436static int
437cd9660_rrip_idflag(p,ana)
438	ISO_RRIP_IDFLAG *p;
439	ISO_RRIP_ANALYZE *ana;
440{
441	ana->fields &= isonum_711(p->flags)|~0xff; /* don't touch high bits */
442	/* special handling of RE field */
443	if (ana->fields&ISO_SUSP_RELDIR)
444		return cd9660_rrip_reldir(/* XXX */ (ISO_RRIP_RELDIR *)p,ana);
445
446	return ISO_SUSP_IDFLAG;
447}
448
449/*
450 * Continuation pointer
451 */
452static int
453cd9660_rrip_cont(p,ana)
454	ISO_RRIP_CONT *p;
455	ISO_RRIP_ANALYZE *ana;
456{
457	ana->iso_ce_blk = isonum_733(p->location);
458	ana->iso_ce_off = isonum_733(p->offset);
459	ana->iso_ce_len = isonum_733(p->length);
460	return ISO_SUSP_CONT;
461}
462
463/*
464 * System Use end
465 */
466static int
467cd9660_rrip_stop(p,ana)
468	ISO_SUSP_HEADER *p;
469	ISO_RRIP_ANALYZE *ana;
470{
471	return ISO_SUSP_STOP;
472}
473
474/*
475 * Extension reference
476 */
477static int
478cd9660_rrip_extref(p,ana)
479	ISO_RRIP_EXTREF *p;
480	ISO_RRIP_ANALYZE *ana;
481{
482	if (isonum_711(p->len_id) != 10
483	    || bcmp((char *)p + 8,"RRIP_1991A",10)
484	    || isonum_711(p->version) != 1)
485		return 0;
486	ana->fields &= ~ISO_SUSP_EXTREF;
487	return ISO_SUSP_EXTREF;
488}
489
490static int
491cd9660_rrip_loop(isodir,ana,table)
492	struct iso_directory_record *isodir;
493	ISO_RRIP_ANALYZE *ana;
494	RRIP_TABLE *table;
495{
496	register RRIP_TABLE *ptable;
497	register ISO_SUSP_HEADER *phead;
498	register ISO_SUSP_HEADER *pend;
499	struct buf *bp = NULL;
500	char *pwhead;
501	u_char c;
502	int result;
503
504	/*
505	 * Note: If name length is odd,
506	 *	 it will be padding 1 byte after the name
507	 */
508	pwhead = isodir->name + isonum_711(isodir->name_len);
509	if (!(isonum_711(isodir->name_len)&1))
510		pwhead++;
511	isochar(isodir->name, pwhead, ana->imp->joliet_level, &c);
512
513	/* If it's not the '.' entry of the root dir obey SP field */
514	if (c != 0 || isonum_733(isodir->extent) != ana->imp->root_extent)
515		pwhead += ana->imp->rr_skip;
516	else
517		pwhead += ana->imp->rr_skip0;
518
519	phead = (ISO_SUSP_HEADER *)pwhead;
520	pend = (ISO_SUSP_HEADER *)((char *)isodir + isonum_711(isodir->length));
521
522	result = 0;
523	while (1) {
524		ana->iso_ce_len = 0;
525		/*
526		 * Note: "pend" should be more than one SUSP header
527		 */
528		while (pend >= phead + 1) {
529			if (isonum_711(phead->version) == 1) {
530				for (ptable = table; ptable->func; ptable++) {
531					if (*phead->type == *ptable->type
532					    && phead->type[1] == ptable->type[1]) {
533						result |= ptable->func(phead,ana);
534						break;
535					}
536				}
537				if (!ana->fields)
538					break;
539			}
540			if (result&ISO_SUSP_STOP) {
541				result &= ~ISO_SUSP_STOP;
542				break;
543			}
544			/* plausibility check */
545			if (isonum_711(phead->length) < sizeof(*phead))
546				break;
547			/*
548			 * move to next SUSP
549			 * Hopefully this works with newer versions, too
550			 */
551			phead = (ISO_SUSP_HEADER *)((char *)phead + isonum_711(phead->length));
552		}
553
554		if (ana->fields && ana->iso_ce_len) {
555			if (ana->iso_ce_blk >= ana->imp->volume_space_size
556			    || ana->iso_ce_off + ana->iso_ce_len > ana->imp->logical_block_size
557			    || bread(ana->imp->im_devvp,
558				     ana->iso_ce_blk <<
559				     (ana->imp->im_bshift - DEV_BSHIFT),
560				     ana->imp->logical_block_size, NOCRED, &bp))
561				/* what to do now? */
562				break;
563			phead = (ISO_SUSP_HEADER *)(bp->b_data + ana->iso_ce_off);
564			pend = (ISO_SUSP_HEADER *) ((char *)phead + ana->iso_ce_len);
565		} else
566			break;
567	}
568	if (bp)
569		brelse(bp);
570	/*
571	 * If we don't find the Basic SUSP stuffs, just set default value
572	 *   (attribute/time stamp)
573	 */
574	for (ptable = table; ptable->func2; ptable++)
575		if (!(ptable->result&result))
576			ptable->func2(isodir,ana);
577
578	return result;
579}
580
581/*
582 * Get Attributes.
583 */
584/*
585 * XXX the casts are bogus but will do for now.
586 */
587#define	BC	(rrt_func_t *)
588static RRIP_TABLE rrip_table_analyze[] = {
589	{ "PX", BC cd9660_rrip_attr,	cd9660_rrip_defattr,	ISO_SUSP_ATTR },
590	{ "TF", BC cd9660_rrip_tstamp,	cd9660_rrip_deftstamp,	ISO_SUSP_TSTAMP },
591	{ "PN", BC cd9660_rrip_device,	0,			ISO_SUSP_DEVICE },
592	{ "RR", BC cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
593	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
594	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
595	{ "",	0,			0,			0 }
596};
597
598int
599cd9660_rrip_analyze(isodir,inop,imp)
600	struct iso_directory_record *isodir;
601	struct iso_node *inop;
602	struct iso_mnt *imp;
603{
604	ISO_RRIP_ANALYZE analyze;
605
606	analyze.inop = inop;
607	analyze.imp = imp;
608	analyze.fields = ISO_SUSP_ATTR|ISO_SUSP_TSTAMP|ISO_SUSP_DEVICE;
609
610	return cd9660_rrip_loop(isodir,&analyze,rrip_table_analyze);
611}
612
613/*
614 * Get Alternate Name.
615 */
616static RRIP_TABLE rrip_table_getname[] = {
617	{ "NM", BC cd9660_rrip_altname,	cd9660_rrip_defname,	ISO_SUSP_ALTNAME },
618	{ "CL", BC cd9660_rrip_pclink,	0,			ISO_SUSP_CLINK|ISO_SUSP_PLINK },
619	{ "PL", BC cd9660_rrip_pclink,	0,			ISO_SUSP_CLINK|ISO_SUSP_PLINK },
620	{ "RE", BC cd9660_rrip_reldir,	0,			ISO_SUSP_RELDIR },
621	{ "RR", BC cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
622	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
623	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
624	{ "",	0,			0,			0 }
625};
626
627int
628cd9660_rrip_getname(isodir,outbuf,outlen,inump,imp)
629	struct iso_directory_record *isodir;
630	char *outbuf;
631	u_short *outlen;
632	ino_t *inump;
633	struct iso_mnt *imp;
634{
635	ISO_RRIP_ANALYZE analyze;
636	RRIP_TABLE *tab;
637	u_char c;
638
639	analyze.outbuf = outbuf;
640	analyze.outlen = outlen;
641	analyze.maxlen = NAME_MAX;
642	analyze.inump = inump;
643	analyze.imp = imp;
644	analyze.fields = ISO_SUSP_ALTNAME|ISO_SUSP_RELDIR|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
645	*outlen = 0;
646
647	isochar(isodir->name, isodir->name + isonum_711(isodir->name_len),
648		imp->joliet_level, &c);
649	tab = rrip_table_getname;
650	if (c == 0 || c == 1) {
651		cd9660_rrip_defname(isodir,&analyze);
652
653		analyze.fields &= ~ISO_SUSP_ALTNAME;
654		tab++;
655	}
656
657	return cd9660_rrip_loop(isodir,&analyze,tab);
658}
659
660/*
661 * Get Symbolic Link.
662 */
663static RRIP_TABLE rrip_table_getsymname[] = {
664	{ "SL", BC cd9660_rrip_slink,	0,			ISO_SUSP_SLINK },
665	{ "RR", BC cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
666	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
667	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
668	{ "",	0,			0,			0 }
669};
670
671int
672cd9660_rrip_getsymname(isodir,outbuf,outlen,imp)
673	struct iso_directory_record *isodir;
674	char *outbuf;
675	u_short *outlen;
676	struct iso_mnt *imp;
677{
678	ISO_RRIP_ANALYZE analyze;
679
680	analyze.outbuf = outbuf;
681	analyze.outlen = outlen;
682	*outlen = 0;
683	analyze.maxlen = MAXPATHLEN;
684	analyze.cont = 1;		/* don't start with a slash */
685	analyze.imp = imp;
686	analyze.fields = ISO_SUSP_SLINK;
687
688	return (cd9660_rrip_loop(isodir,&analyze,rrip_table_getsymname)&ISO_SUSP_SLINK);
689}
690
691static RRIP_TABLE rrip_table_extref[] = {
692	{ "ER", BC cd9660_rrip_extref,	0,			ISO_SUSP_EXTREF },
693	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
694	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
695	{ "",	0,			0,			0 }
696};
697
698/*
699 * Check for Rock Ridge Extension and return offset of its fields.
700 * Note: We insist on the ER field.
701 */
702int
703cd9660_rrip_offset(isodir,imp)
704	struct iso_directory_record *isodir;
705	struct iso_mnt *imp;
706{
707	ISO_RRIP_OFFSET *p;
708	ISO_RRIP_ANALYZE analyze;
709
710	imp->rr_skip0 = 0;
711	p = (ISO_RRIP_OFFSET *)(isodir->name + 1);
712	if (bcmp(p,"SP\7\1\276\357",6)) {
713		/* Maybe, it's a CDROM XA disc? */
714		imp->rr_skip0 = 15;
715		p = (ISO_RRIP_OFFSET *)((char *)p + 15);
716		if (bcmp(p,"SP\7\1\276\357",6))
717			return -1;
718	}
719
720	analyze.imp = imp;
721	analyze.fields = ISO_SUSP_EXTREF;
722	if (!(cd9660_rrip_loop(isodir,&analyze,rrip_table_extref)&ISO_SUSP_EXTREF))
723		return -1;
724
725	return isonum_711(p->skip);
726}
727