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