freebsd-skq/sys/isofs/cd9660/cd9660_rrip.c
joerg 0ec2804cee When encountering a ISO_SUSP_CFLAG_ROOT element in Rock Ridge
processing, this actually means there's a double slash recorded in the
symbolic link's path name.  We used to start over from / then, which
caused link targets like ../../bsdi.1.0/include//pathnames.h to be
interpreted as /pathnahes.h.  This is both contradictionary to our
conventional slash interpretation, as well as potentially dangerous.

The right thing to do is (obviously) to just ignore that element.

bde once pointed out that mistake when he noticed it on the
4.4BSD-Lite2 CD-ROM, and asked me for help.

Reviewed by:	bde (about half a year ago)
MFC after:	3 days
2006-03-13 22:32:33 +00:00

716 lines
18 KiB
C

/*-
* Copyright (c) 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley
* by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
* Support code is derived from software contributed to Berkeley
* by Atsushi Murai (amurai@spec.co.jp).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)cd9660_rrip.c 8.6 (Berkeley) 12/5/94
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/kernel.h>
#include <isofs/cd9660/iso.h>
#include <isofs/cd9660/cd9660_node.h>
#include <isofs/cd9660/cd9660_rrip.h>
#include <isofs/cd9660/iso_rrip.h>
typedef int rrt_func_t(void *, ISO_RRIP_ANALYZE *ana);
typedef struct {
char type[2];
rrt_func_t *func;
void (*func2)(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana);
int result;
} RRIP_TABLE;
static int cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, ISO_RRIP_ANALYZE *ana);
static int cd9660_rrip_attr(ISO_RRIP_ATTR *p, ISO_RRIP_ANALYZE *ana);
static int cd9660_rrip_cont(ISO_RRIP_CONT *p, ISO_RRIP_ANALYZE *ana);
static void cd9660_rrip_defattr(struct iso_directory_record *isodir,
ISO_RRIP_ANALYZE *ana);
static void cd9660_rrip_defname(struct iso_directory_record *isodir,
ISO_RRIP_ANALYZE *ana);
static void cd9660_rrip_deftstamp(struct iso_directory_record *isodir,
ISO_RRIP_ANALYZE *ana);
static int cd9660_rrip_device(ISO_RRIP_DEVICE *p, ISO_RRIP_ANALYZE *ana);
static int cd9660_rrip_extref(ISO_RRIP_EXTREF *p, ISO_RRIP_ANALYZE *ana);
static int cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, ISO_RRIP_ANALYZE *ana);
static int cd9660_rrip_loop(struct iso_directory_record *isodir,
ISO_RRIP_ANALYZE *ana, RRIP_TABLE *table);
static int cd9660_rrip_pclink(ISO_RRIP_CLINK *p, ISO_RRIP_ANALYZE *ana);
static int cd9660_rrip_reldir(ISO_RRIP_RELDIR *p, ISO_RRIP_ANALYZE *ana);
static int cd9660_rrip_slink(ISO_RRIP_SLINK *p, ISO_RRIP_ANALYZE *ana);
static int cd9660_rrip_stop(ISO_SUSP_HEADER *p, ISO_RRIP_ANALYZE *ana);
static int cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, ISO_RRIP_ANALYZE *ana);
/*
* POSIX file attribute
*/
static int
cd9660_rrip_attr(p,ana)
ISO_RRIP_ATTR *p;
ISO_RRIP_ANALYZE *ana;
{
ana->inop->inode.iso_mode = isonum_733(p->mode);
ana->inop->inode.iso_uid = isonum_733(p->uid);
ana->inop->inode.iso_gid = isonum_733(p->gid);
ana->inop->inode.iso_links = isonum_733(p->links);
ana->fields &= ~ISO_SUSP_ATTR;
return ISO_SUSP_ATTR;
}
static void
cd9660_rrip_defattr(isodir,ana)
struct iso_directory_record *isodir;
ISO_RRIP_ANALYZE *ana;
{
/* But this is a required field! */
printf("RRIP without PX field?\n");
cd9660_defattr(isodir,ana->inop,NULL,ISO_FTYPE_RRIP);
}
/*
* Symbolic Links
*/
static int
cd9660_rrip_slink(p,ana)
ISO_RRIP_SLINK *p;
ISO_RRIP_ANALYZE *ana;
{
ISO_RRIP_SLINK_COMPONENT *pcomp;
ISO_RRIP_SLINK_COMPONENT *pcompe;
int len, wlen, cont;
char *outbuf, *inbuf;
pcomp = (ISO_RRIP_SLINK_COMPONENT *)p->component;
pcompe = (ISO_RRIP_SLINK_COMPONENT *)((char *)p + isonum_711(p->h.length));
len = *ana->outlen;
outbuf = ana->outbuf;
cont = ana->cont;
/*
* Gathering a Symbolic name from each component with path
*/
for (;
pcomp < pcompe;
pcomp = (ISO_RRIP_SLINK_COMPONENT *)((char *)pcomp + ISO_RRIP_SLSIZ
+ isonum_711(pcomp->clen))) {
if (!cont) {
if (len < ana->maxlen) {
len++;
*outbuf++ = '/';
}
}
cont = 0;
inbuf = "..";
wlen = 0;
switch (*pcomp->cflag) {
case ISO_SUSP_CFLAG_CURRENT:
/* Inserting Current */
wlen = 1;
break;
case ISO_SUSP_CFLAG_PARENT:
/* Inserting Parent */
wlen = 2;
break;
case ISO_SUSP_CFLAG_ROOT:
/* Inserting slash for ROOT */
/* Double slash, nothing really to do here. */
break;
case ISO_SUSP_CFLAG_VOLROOT:
/* Inserting a mount point i.e. "/cdrom" */
/* same as above */
outbuf -= len;
len = 0;
inbuf = ana->imp->im_mountp->mnt_stat.f_mntonname;
wlen = strlen(inbuf);
break;
case ISO_SUSP_CFLAG_HOST:
/* Inserting hostname i.e. "kurt.tools.de" */
inbuf = hostname;
wlen = strlen(hostname);
break;
case ISO_SUSP_CFLAG_CONTINUE:
cont = 1;
/* FALLTHROUGH */
case 0:
/* Inserting component */
wlen = isonum_711(pcomp->clen);
inbuf = pcomp->name;
break;
default:
printf("RRIP with incorrect flags?");
wlen = ana->maxlen + 1;
break;
}
if (len + wlen > ana->maxlen) {
/* indicate error to caller */
ana->cont = 1;
ana->fields = 0;
ana->outbuf -= *ana->outlen;
*ana->outlen = 0;
return 0;
}
bcopy(inbuf,outbuf,wlen);
outbuf += wlen;
len += wlen;
}
ana->outbuf = outbuf;
*ana->outlen = len;
ana->cont = cont;
if (!isonum_711(p->flags)) {
ana->fields &= ~ISO_SUSP_SLINK;
return ISO_SUSP_SLINK;
}
return 0;
}
/*
* Alternate name
*/
static int
cd9660_rrip_altname(p,ana)
ISO_RRIP_ALTNAME *p;
ISO_RRIP_ANALYZE *ana;
{
char *inbuf;
int wlen;
int cont;
inbuf = "..";
wlen = 0;
cont = 0;
switch (*p->flags) {
case ISO_SUSP_CFLAG_CURRENT:
/* Inserting Current */
wlen = 1;
break;
case ISO_SUSP_CFLAG_PARENT:
/* Inserting Parent */
wlen = 2;
break;
case ISO_SUSP_CFLAG_HOST:
/* Inserting hostname i.e. "kurt.tools.de" */
inbuf = hostname;
wlen = strlen(hostname);
break;
case ISO_SUSP_CFLAG_CONTINUE:
cont = 1;
/* FALLTHROUGH */
case 0:
/* Inserting component */
wlen = isonum_711(p->h.length) - 5;
inbuf = (char *)p + 5;
break;
default:
printf("RRIP with incorrect NM flags?\n");
wlen = ana->maxlen + 1;
break;
}
if ((*ana->outlen += wlen) > ana->maxlen) {
/* treat as no name field */
ana->fields &= ~ISO_SUSP_ALTNAME;
ana->outbuf -= *ana->outlen - wlen;
*ana->outlen = 0;
return 0;
}
bcopy(inbuf,ana->outbuf,wlen);
ana->outbuf += wlen;
if (!cont) {
ana->fields &= ~ISO_SUSP_ALTNAME;
return ISO_SUSP_ALTNAME;
}
return 0;
}
static void
cd9660_rrip_defname(isodir,ana)
struct iso_directory_record *isodir;
ISO_RRIP_ANALYZE *ana;
{
isofntrans(isodir->name,isonum_711(isodir->name_len),
ana->outbuf,ana->outlen,
1,isonum_711(isodir->flags)&4, ana->imp->joliet_level,
ana->imp->im_flags, ana->imp->im_d2l);
switch (*ana->outbuf) {
default:
break;
case 1:
*ana->outlen = 2;
/* FALLTHROUGH */
case 0:
/* outlen is 1 already */
strcpy(ana->outbuf,"..");
break;
}
}
/*
* Parent or Child Link
*/
static int
cd9660_rrip_pclink(p,ana)
ISO_RRIP_CLINK *p;
ISO_RRIP_ANALYZE *ana;
{
*ana->inump = isonum_733(p->dir_loc) << ana->imp->im_bshift;
ana->fields &= ~(ISO_SUSP_CLINK|ISO_SUSP_PLINK);
return *p->h.type == 'C' ? ISO_SUSP_CLINK : ISO_SUSP_PLINK;
}
/*
* Relocated directory
*/
static int
cd9660_rrip_reldir(p,ana)
ISO_RRIP_RELDIR *p;
ISO_RRIP_ANALYZE *ana;
{
/* special hack to make caller aware of RE field */
*ana->outlen = 0;
ana->fields = 0;
return ISO_SUSP_RELDIR|ISO_SUSP_ALTNAME|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
}
static int
cd9660_rrip_tstamp(p,ana)
ISO_RRIP_TSTAMP *p;
ISO_RRIP_ANALYZE *ana;
{
u_char *ptime;
ptime = p->time;
/* Check a format of time stamp (7bytes/17bytes) */
if (!(*p->flags&ISO_SUSP_TSTAMP_FORM17)) {
if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
ptime += 7;
if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_mtime,
ISO_FTYPE_RRIP);
ptime += 7;
} else
bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec));
if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_atime,
ISO_FTYPE_RRIP);
ptime += 7;
} else
ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_ctime,
ISO_FTYPE_RRIP);
else
ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
} else {
if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
ptime += 17;
if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_mtime);
ptime += 17;
} else
bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec));
if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_atime);
ptime += 17;
} else
ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_ctime);
else
ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
}
ana->fields &= ~ISO_SUSP_TSTAMP;
return ISO_SUSP_TSTAMP;
}
static void
cd9660_rrip_deftstamp(isodir,ana)
struct iso_directory_record *isodir;
ISO_RRIP_ANALYZE *ana;
{
cd9660_deftstamp(isodir,ana->inop,NULL,ISO_FTYPE_RRIP);
}
/*
* POSIX device modes
*/
static int
cd9660_rrip_device(p,ana)
ISO_RRIP_DEVICE *p;
ISO_RRIP_ANALYZE *ana;
{
u_int high, low;
high = isonum_733(p->dev_t_high);
low = isonum_733(p->dev_t_low);
if (high == 0)
ana->inop->inode.iso_rdev = makedev(umajor(low), uminor(low));
else
ana->inop->inode.iso_rdev = makedev(high, uminor(low));
ana->fields &= ~ISO_SUSP_DEVICE;
return ISO_SUSP_DEVICE;
}
/*
* Flag indicating
*/
static int
cd9660_rrip_idflag(p,ana)
ISO_RRIP_IDFLAG *p;
ISO_RRIP_ANALYZE *ana;
{
ana->fields &= isonum_711(p->flags)|~0xff; /* don't touch high bits */
/* special handling of RE field */
if (ana->fields&ISO_SUSP_RELDIR)
return cd9660_rrip_reldir(/* XXX */ (ISO_RRIP_RELDIR *)p,ana);
return ISO_SUSP_IDFLAG;
}
/*
* Continuation pointer
*/
static int
cd9660_rrip_cont(p,ana)
ISO_RRIP_CONT *p;
ISO_RRIP_ANALYZE *ana;
{
ana->iso_ce_blk = isonum_733(p->location);
ana->iso_ce_off = isonum_733(p->offset);
ana->iso_ce_len = isonum_733(p->length);
return ISO_SUSP_CONT;
}
/*
* System Use end
*/
static int
cd9660_rrip_stop(p,ana)
ISO_SUSP_HEADER *p;
ISO_RRIP_ANALYZE *ana;
{
return ISO_SUSP_STOP;
}
/*
* Extension reference
*/
static int
cd9660_rrip_extref(p,ana)
ISO_RRIP_EXTREF *p;
ISO_RRIP_ANALYZE *ana;
{
if (isonum_711(p->len_id) != 10
|| bcmp((char *)p + 8,"RRIP_1991A",10)
|| isonum_711(p->version) != 1)
return 0;
ana->fields &= ~ISO_SUSP_EXTREF;
return ISO_SUSP_EXTREF;
}
static int
cd9660_rrip_loop(isodir,ana,table)
struct iso_directory_record *isodir;
ISO_RRIP_ANALYZE *ana;
RRIP_TABLE *table;
{
RRIP_TABLE *ptable;
ISO_SUSP_HEADER *phead;
ISO_SUSP_HEADER *pend;
struct buf *bp = NULL;
char *pwhead;
u_short c;
int result;
/*
* Note: If name length is odd,
* it will be padding 1 byte after the name
*/
pwhead = isodir->name + isonum_711(isodir->name_len);
if (!(isonum_711(isodir->name_len)&1))
pwhead++;
isochar(isodir->name, pwhead, ana->imp->joliet_level, &c, NULL,
ana->imp->im_flags, ana->imp->im_d2l);
/* If it's not the '.' entry of the root dir obey SP field */
if (c != 0 || isonum_733(isodir->extent) != ana->imp->root_extent)
pwhead += ana->imp->rr_skip;
else
pwhead += ana->imp->rr_skip0;
phead = (ISO_SUSP_HEADER *)pwhead;
pend = (ISO_SUSP_HEADER *)((char *)isodir + isonum_711(isodir->length));
result = 0;
while (1) {
ana->iso_ce_len = 0;
/*
* Note: "pend" should be more than one SUSP header
*/
while (pend >= phead + 1) {
if (isonum_711(phead->version) == 1) {
for (ptable = table; ptable->func; ptable++) {
if (*phead->type == *ptable->type
&& phead->type[1] == ptable->type[1]) {
result |= ptable->func(phead,ana);
break;
}
}
if (!ana->fields)
break;
}
if (result&ISO_SUSP_STOP) {
result &= ~ISO_SUSP_STOP;
break;
}
/* plausibility check */
if (isonum_711(phead->length) < sizeof(*phead))
break;
/*
* move to next SUSP
* Hopefully this works with newer versions, too
*/
phead = (ISO_SUSP_HEADER *)((char *)phead + isonum_711(phead->length));
}
if (ana->fields && ana->iso_ce_len) {
if (ana->iso_ce_blk >= ana->imp->volume_space_size
|| ana->iso_ce_off + ana->iso_ce_len > ana->imp->logical_block_size
|| bread(ana->imp->im_devvp,
ana->iso_ce_blk <<
(ana->imp->im_bshift - DEV_BSHIFT),
ana->imp->logical_block_size, NOCRED, &bp))
/* what to do now? */
break;
phead = (ISO_SUSP_HEADER *)(bp->b_data + ana->iso_ce_off);
pend = (ISO_SUSP_HEADER *) ((char *)phead + ana->iso_ce_len);
} else
break;
}
if (bp)
brelse(bp);
/*
* If we don't find the Basic SUSP stuffs, just set default value
* (attribute/time stamp)
*/
for (ptable = table; ptable->func2; ptable++)
if (!(ptable->result&result))
ptable->func2(isodir,ana);
return result;
}
/*
* Get Attributes.
*/
/*
* XXX the casts are bogus but will do for now.
*/
#define BC (rrt_func_t *)
static RRIP_TABLE rrip_table_analyze[] = {
{ "PX", BC cd9660_rrip_attr, cd9660_rrip_defattr, ISO_SUSP_ATTR },
{ "TF", BC cd9660_rrip_tstamp, cd9660_rrip_deftstamp, ISO_SUSP_TSTAMP },
{ "PN", BC cd9660_rrip_device, 0, ISO_SUSP_DEVICE },
{ "RR", BC cd9660_rrip_idflag, 0, ISO_SUSP_IDFLAG },
{ "CE", BC cd9660_rrip_cont, 0, ISO_SUSP_CONT },
{ "ST", BC cd9660_rrip_stop, 0, ISO_SUSP_STOP },
{ "", 0, 0, 0 }
};
int
cd9660_rrip_analyze(isodir,inop,imp)
struct iso_directory_record *isodir;
struct iso_node *inop;
struct iso_mnt *imp;
{
ISO_RRIP_ANALYZE analyze;
analyze.inop = inop;
analyze.imp = imp;
analyze.fields = ISO_SUSP_ATTR|ISO_SUSP_TSTAMP|ISO_SUSP_DEVICE;
return cd9660_rrip_loop(isodir,&analyze,rrip_table_analyze);
}
/*
* Get Alternate Name.
*/
static RRIP_TABLE rrip_table_getname[] = {
{ "NM", BC cd9660_rrip_altname, cd9660_rrip_defname, ISO_SUSP_ALTNAME },
{ "CL", BC cd9660_rrip_pclink, 0, ISO_SUSP_CLINK|ISO_SUSP_PLINK },
{ "PL", BC cd9660_rrip_pclink, 0, ISO_SUSP_CLINK|ISO_SUSP_PLINK },
{ "RE", BC cd9660_rrip_reldir, 0, ISO_SUSP_RELDIR },
{ "RR", BC cd9660_rrip_idflag, 0, ISO_SUSP_IDFLAG },
{ "CE", BC cd9660_rrip_cont, 0, ISO_SUSP_CONT },
{ "ST", BC cd9660_rrip_stop, 0, ISO_SUSP_STOP },
{ "", 0, 0, 0 }
};
int
cd9660_rrip_getname(isodir,outbuf,outlen,inump,imp)
struct iso_directory_record *isodir;
char *outbuf;
u_short *outlen;
ino_t *inump;
struct iso_mnt *imp;
{
ISO_RRIP_ANALYZE analyze;
RRIP_TABLE *tab;
u_short c;
analyze.outbuf = outbuf;
analyze.outlen = outlen;
analyze.maxlen = NAME_MAX;
analyze.inump = inump;
analyze.imp = imp;
analyze.fields = ISO_SUSP_ALTNAME|ISO_SUSP_RELDIR|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
*outlen = 0;
isochar(isodir->name, isodir->name + isonum_711(isodir->name_len),
imp->joliet_level, &c, NULL, imp->im_flags, imp->im_d2l);
tab = rrip_table_getname;
if (c == 0 || c == 1) {
cd9660_rrip_defname(isodir,&analyze);
analyze.fields &= ~ISO_SUSP_ALTNAME;
tab++;
}
return cd9660_rrip_loop(isodir,&analyze,tab);
}
/*
* Get Symbolic Link.
*/
static RRIP_TABLE rrip_table_getsymname[] = {
{ "SL", BC cd9660_rrip_slink, 0, ISO_SUSP_SLINK },
{ "RR", BC cd9660_rrip_idflag, 0, ISO_SUSP_IDFLAG },
{ "CE", BC cd9660_rrip_cont, 0, ISO_SUSP_CONT },
{ "ST", BC cd9660_rrip_stop, 0, ISO_SUSP_STOP },
{ "", 0, 0, 0 }
};
int
cd9660_rrip_getsymname(isodir,outbuf,outlen,imp)
struct iso_directory_record *isodir;
char *outbuf;
u_short *outlen;
struct iso_mnt *imp;
{
ISO_RRIP_ANALYZE analyze;
analyze.outbuf = outbuf;
analyze.outlen = outlen;
*outlen = 0;
analyze.maxlen = MAXPATHLEN;
analyze.cont = 1; /* don't start with a slash */
analyze.imp = imp;
analyze.fields = ISO_SUSP_SLINK;
return (cd9660_rrip_loop(isodir,&analyze,rrip_table_getsymname)&ISO_SUSP_SLINK);
}
static RRIP_TABLE rrip_table_extref[] = {
{ "ER", BC cd9660_rrip_extref, 0, ISO_SUSP_EXTREF },
{ "CE", BC cd9660_rrip_cont, 0, ISO_SUSP_CONT },
{ "ST", BC cd9660_rrip_stop, 0, ISO_SUSP_STOP },
{ "", 0, 0, 0 }
};
/*
* Check for Rock Ridge Extension and return offset of its fields.
* Note: We insist on the ER field.
*/
int
cd9660_rrip_offset(isodir,imp)
struct iso_directory_record *isodir;
struct iso_mnt *imp;
{
ISO_RRIP_OFFSET *p;
ISO_RRIP_ANALYZE analyze;
imp->rr_skip0 = 0;
p = (ISO_RRIP_OFFSET *)(isodir->name + 1);
if (bcmp(p,"SP\7\1\276\357",6)) {
/* Maybe, it's a CDROM XA disc? */
imp->rr_skip0 = 15;
p = (ISO_RRIP_OFFSET *)((char *)p + 15);
if (bcmp(p,"SP\7\1\276\357",6))
return -1;
}
analyze.imp = imp;
analyze.fields = ISO_SUSP_EXTREF;
if (!(cd9660_rrip_loop(isodir,&analyze,rrip_table_extref)&ISO_SUSP_EXTREF))
return -1;
return isonum_711(p->skip);
}