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