cd9660_rrip.c revision 8876
11541Srgrimes/*-
21541Srgrimes * Copyright (c) 1993, 1994
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * This code is derived from software contributed to Berkeley
61541Srgrimes * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
71541Srgrimes * Support code is derived from software contributed to Berkeley
81541Srgrimes * by Atsushi Murai (amurai@spec.co.jp).
91541Srgrimes *
101541Srgrimes * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 3. All advertising materials mentioning features or use of this software
191541Srgrimes *    must display the following acknowledgement:
201541Srgrimes *	This product includes software developed by the University of
211541Srgrimes *	California, Berkeley and its contributors.
221541Srgrimes * 4. Neither the name of the University nor the names of its contributors
231541Srgrimes *    may be used to endorse or promote products derived from this software
241541Srgrimes *    without specific prior written permission.
251541Srgrimes *
261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361541Srgrimes * SUCH DAMAGE.
371541Srgrimes *
381541Srgrimes *	@(#)cd9660_rrip.c	8.2 (Berkeley) 1/23/94
398876Srgrimes * $Id: cd9660_rrip.c,v 1.6 1995/01/16 17:03:26 joerg Exp $
401541Srgrimes */
411541Srgrimes
421541Srgrimes#include <sys/param.h>
432806Sbde#include <sys/systm.h>
441541Srgrimes#include <sys/namei.h>
451541Srgrimes#include <sys/buf.h>
461541Srgrimes#include <sys/file.h>
471541Srgrimes#include <sys/vnode.h>
481541Srgrimes#include <sys/mount.h>
491541Srgrimes#include <sys/kernel.h>
501541Srgrimes#include <sys/stat.h>
511541Srgrimes#include <sys/types.h>
521541Srgrimes
531541Srgrimes#include <sys/time.h>
541541Srgrimes
551541Srgrimes#include <isofs/cd9660/iso.h>
561541Srgrimes#include <isofs/cd9660/cd9660_node.h>
571541Srgrimes#include <isofs/cd9660/cd9660_rrip.h>
581541Srgrimes#include <isofs/cd9660/iso_rrip.h>
591541Srgrimes
601541Srgrimes/*
611541Srgrimes * POSIX file attribute
621541Srgrimes */
631541Srgrimesstatic int
641541Srgrimescd9660_rrip_attr(p,ana)
651541Srgrimes	ISO_RRIP_ATTR *p;
661541Srgrimes	ISO_RRIP_ANALYZE *ana;
671541Srgrimes{
681541Srgrimes	ana->inop->inode.iso_mode = isonum_731(p->mode_l);
691541Srgrimes	ana->inop->inode.iso_uid = (uid_t)isonum_731(p->uid_l);
701541Srgrimes	ana->inop->inode.iso_gid = (gid_t)isonum_731(p->gid_l);
711541Srgrimes	ana->inop->inode.iso_links = isonum_731(p->links_l);
721541Srgrimes	ana->fields &= ~ISO_SUSP_ATTR;
731541Srgrimes	return ISO_SUSP_ATTR;
741541Srgrimes}
751541Srgrimes
761541Srgrimesstatic void
771541Srgrimescd9660_rrip_defattr(isodir,ana)
781541Srgrimes	struct iso_directory_record *isodir;
791541Srgrimes	ISO_RRIP_ANALYZE *ana;
801541Srgrimes{
811541Srgrimes	/* But this is a required field! */
821541Srgrimes	printf("RRIP without PX field?\n");
835651Sjoerg	cd9660_defattr(isodir,ana->inop,NULL,ISO_FTYPE_RRIP);
841541Srgrimes}
851541Srgrimes
861541Srgrimes/*
871541Srgrimes * Symbolic Links
881541Srgrimes */
891541Srgrimesstatic int
901541Srgrimescd9660_rrip_slink(p,ana)
915651Sjoerg	ISO_RRIP_SLINK	*p;
921541Srgrimes	ISO_RRIP_ANALYZE *ana;
931541Srgrimes{
941541Srgrimes	register ISO_RRIP_SLINK_COMPONENT *pcomp;
951541Srgrimes	register ISO_RRIP_SLINK_COMPONENT *pcompe;
961541Srgrimes	int len, wlen, cont;
971541Srgrimes	char *outbuf, *inbuf;
988876Srgrimes
991541Srgrimes	pcomp = (ISO_RRIP_SLINK_COMPONENT *)p->component;
1001541Srgrimes	pcompe = (ISO_RRIP_SLINK_COMPONENT *)((char *)p + isonum_711(p->h.length));
1011541Srgrimes	len = *ana->outlen;
1021541Srgrimes	outbuf = ana->outbuf;
1031541Srgrimes	cont = ana->cont;
1048876Srgrimes
1051541Srgrimes	/*
1061541Srgrimes	 * Gathering a Symbolic name from each component with path
1071541Srgrimes	 */
1081541Srgrimes	for (;
1091541Srgrimes	     pcomp < pcompe;
1101541Srgrimes	     pcomp = (ISO_RRIP_SLINK_COMPONENT *)((char *)pcomp + ISO_RRIP_SLSIZ
1111541Srgrimes						  + isonum_711(pcomp->clen))) {
1128876Srgrimes
1131541Srgrimes		if (!cont) {
1141541Srgrimes			if (len < ana->maxlen) {
1151541Srgrimes				len++;
1161541Srgrimes				*outbuf++ = '/';
1171541Srgrimes			}
1181541Srgrimes		}
1191541Srgrimes		cont = 0;
1208876Srgrimes
1211541Srgrimes		inbuf = "..";
1221541Srgrimes		wlen = 0;
1238876Srgrimes
1241541Srgrimes		switch (*pcomp->cflag) {
1258876Srgrimes
1261541Srgrimes		case ISO_SUSP_CFLAG_CURRENT:
1271541Srgrimes			/* Inserting Current */
1281541Srgrimes			wlen = 1;
1291541Srgrimes			break;
1308876Srgrimes
1311541Srgrimes		case ISO_SUSP_CFLAG_PARENT:
1321541Srgrimes			/* Inserting Parent */
1331541Srgrimes			wlen = 2;
1341541Srgrimes			break;
1358876Srgrimes
1361541Srgrimes		case ISO_SUSP_CFLAG_ROOT:
1371541Srgrimes			/* Inserting slash for ROOT */
1381541Srgrimes			/* start over from beginning(?) */
1391541Srgrimes			outbuf -= len;
1401541Srgrimes			len = 0;
1411541Srgrimes			break;
1428876Srgrimes
1431541Srgrimes		case ISO_SUSP_CFLAG_VOLROOT:
1441541Srgrimes			/* Inserting a mount point i.e. "/cdrom" */
1451541Srgrimes			/* same as above */
1461541Srgrimes			outbuf -= len;
1471541Srgrimes			len = 0;
1481541Srgrimes			inbuf = ana->imp->im_mountp->mnt_stat.f_mntonname;
1491541Srgrimes			wlen = strlen(inbuf);
1501541Srgrimes			break;
1518876Srgrimes
1521541Srgrimes		case ISO_SUSP_CFLAG_HOST:
1531541Srgrimes			/* Inserting hostname i.e. "kurt.tools.de" */
1541541Srgrimes			inbuf = hostname;
1551541Srgrimes			wlen = hostnamelen;
1561541Srgrimes			break;
1578876Srgrimes
1581541Srgrimes		case ISO_SUSP_CFLAG_CONTINUE:
1591541Srgrimes			cont = 1;
1601541Srgrimes			/* fall thru */
1611541Srgrimes		case 0:
1621541Srgrimes			/* Inserting component */
1631541Srgrimes			wlen = isonum_711(pcomp->clen);
1641541Srgrimes			inbuf = pcomp->name;
1651541Srgrimes			break;
1661541Srgrimes		default:
1671541Srgrimes			printf("RRIP with incorrect flags?");
1681541Srgrimes			wlen = ana->maxlen + 1;
1691541Srgrimes			break;
1701541Srgrimes		}
1718876Srgrimes
1721541Srgrimes		if (len + wlen > ana->maxlen) {
1731541Srgrimes			/* indicate error to caller */
1741541Srgrimes			ana->cont = 1;
1751541Srgrimes			ana->fields = 0;
1761541Srgrimes			ana->outbuf -= *ana->outlen;
1771541Srgrimes			*ana->outlen = 0;
1781541Srgrimes			return 0;
1791541Srgrimes		}
1808876Srgrimes
1811541Srgrimes		bcopy(inbuf,outbuf,wlen);
1821541Srgrimes		outbuf += wlen;
1831541Srgrimes		len += wlen;
1848876Srgrimes
1851541Srgrimes	}
1861541Srgrimes	ana->outbuf = outbuf;
1871541Srgrimes	*ana->outlen = len;
1881541Srgrimes	ana->cont = cont;
1898876Srgrimes
1901541Srgrimes	if (!isonum_711(p->flags)) {
1911541Srgrimes		ana->fields &= ~ISO_SUSP_SLINK;
1921541Srgrimes		return ISO_SUSP_SLINK;
1931541Srgrimes	}
1941541Srgrimes	return 0;
1951541Srgrimes}
1961541Srgrimes
1971541Srgrimes/*
1981541Srgrimes * Alternate name
1991541Srgrimes */
2001541Srgrimesstatic int
2011541Srgrimescd9660_rrip_altname(p,ana)
2021541Srgrimes	ISO_RRIP_ALTNAME *p;
2031541Srgrimes	ISO_RRIP_ANALYZE *ana;
2041541Srgrimes{
2051541Srgrimes	char *inbuf;
2061541Srgrimes	int wlen;
2071541Srgrimes	int cont;
2088876Srgrimes
2091541Srgrimes	inbuf = "..";
2101541Srgrimes	wlen = 0;
2111541Srgrimes	cont = 0;
2128876Srgrimes
2131541Srgrimes	switch (*p->flags) {
2141541Srgrimes	case ISO_SUSP_CFLAG_CURRENT:
2151541Srgrimes		/* Inserting Current */
2161541Srgrimes		wlen = 1;
2171541Srgrimes		break;
2188876Srgrimes
2191541Srgrimes	case ISO_SUSP_CFLAG_PARENT:
2201541Srgrimes		/* Inserting Parent */
2211541Srgrimes		wlen = 2;
2221541Srgrimes		break;
2238876Srgrimes
2241541Srgrimes	case ISO_SUSP_CFLAG_HOST:
2251541Srgrimes		/* Inserting hostname i.e. "kurt.tools.de" */
2261541Srgrimes		inbuf = hostname;
2271541Srgrimes		wlen = hostnamelen;
2281541Srgrimes		break;
2298876Srgrimes
2301541Srgrimes	case ISO_SUSP_CFLAG_CONTINUE:
2311541Srgrimes		cont = 1;
2321541Srgrimes		/* fall thru */
2331541Srgrimes	case 0:
2341541Srgrimes		/* Inserting component */
2351541Srgrimes		wlen = isonum_711(p->h.length) - 5;
2361541Srgrimes		inbuf = (char *)p + 5;
2371541Srgrimes		break;
2388876Srgrimes
2391541Srgrimes	default:
2401541Srgrimes		printf("RRIP with incorrect NM flags?\n");
2411541Srgrimes		wlen = ana->maxlen + 1;
2421541Srgrimes		break;
2431541Srgrimes	}
2448876Srgrimes
2451541Srgrimes	if ((*ana->outlen += wlen) > ana->maxlen) {
2461541Srgrimes		/* treat as no name field */
2471541Srgrimes		ana->fields &= ~ISO_SUSP_ALTNAME;
2481541Srgrimes		ana->outbuf -= *ana->outlen - wlen;
2491541Srgrimes		*ana->outlen = 0;
2501541Srgrimes		return 0;
2511541Srgrimes	}
2528876Srgrimes
2531541Srgrimes	bcopy(inbuf,ana->outbuf,wlen);
2541541Srgrimes	ana->outbuf += wlen;
2558876Srgrimes
2561541Srgrimes	if (!cont) {
2571541Srgrimes		ana->fields &= ~ISO_SUSP_ALTNAME;
2581541Srgrimes		return ISO_SUSP_ALTNAME;
2591541Srgrimes	}
2601541Srgrimes	return 0;
2611541Srgrimes}
2621541Srgrimes
2631541Srgrimesstatic void
2641541Srgrimescd9660_rrip_defname(isodir,ana)
2651541Srgrimes	struct iso_directory_record *isodir;
2661541Srgrimes	ISO_RRIP_ANALYZE *ana;
2671541Srgrimes{
2681541Srgrimes	strcpy(ana->outbuf,"..");
2691541Srgrimes	switch (*isodir->name) {
2701541Srgrimes	default:
2711541Srgrimes		isofntrans(isodir->name,isonum_711(isodir->name_len),
2721541Srgrimes			   ana->outbuf,ana->outlen,
2731541Srgrimes			   1,isonum_711(isodir->flags)&4);
2741541Srgrimes		break;
2751541Srgrimes	case 0:
2761541Srgrimes		*ana->outlen = 1;
2771541Srgrimes		break;
2781541Srgrimes	case 1:
2791541Srgrimes		*ana->outlen = 2;
2801541Srgrimes		break;
2811541Srgrimes	}
2821541Srgrimes}
2831541Srgrimes
2841541Srgrimes/*
2851541Srgrimes * Parent or Child Link
2861541Srgrimes */
2871541Srgrimesstatic int
2881541Srgrimescd9660_rrip_pclink(p,ana)
2895651Sjoerg	ISO_RRIP_CLINK	*p;
2901541Srgrimes	ISO_RRIP_ANALYZE *ana;
2911541Srgrimes{
2921541Srgrimes	*ana->inump = isonum_733(p->dir_loc) << ana->imp->im_bshift;
2931541Srgrimes	ana->fields &= ~(ISO_SUSP_CLINK|ISO_SUSP_PLINK);
2941541Srgrimes	return *p->h.type == 'C' ? ISO_SUSP_CLINK : ISO_SUSP_PLINK;
2951541Srgrimes}
2961541Srgrimes
2971541Srgrimes/*
2981541Srgrimes * Relocated directory
2991541Srgrimes */
3001541Srgrimesstatic int
3011541Srgrimescd9660_rrip_reldir(p,ana)
3025651Sjoerg	ISO_RRIP_RELDIR	 *p;
3031541Srgrimes	ISO_RRIP_ANALYZE *ana;
3041541Srgrimes{
3051541Srgrimes	/* special hack to make caller aware of RE field */
3061541Srgrimes	*ana->outlen = 0;
3071541Srgrimes	ana->fields = 0;
3081541Srgrimes	return ISO_SUSP_RELDIR|ISO_SUSP_ALTNAME|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
3091541Srgrimes}
3101541Srgrimes
3111541Srgrimesstatic int
3121541Srgrimescd9660_rrip_tstamp(p,ana)
3131541Srgrimes	ISO_RRIP_TSTAMP *p;
3141541Srgrimes	ISO_RRIP_ANALYZE *ana;
3151541Srgrimes{
3161541Srgrimes	unsigned char *ptime;
3178876Srgrimes
3181541Srgrimes	ptime = p->time;
3198876Srgrimes
3201541Srgrimes	/* Check a format of time stamp (7bytes/17bytes) */
3211541Srgrimes	if (!(*p->flags&ISO_SUSP_TSTAMP_FORM17)) {
3221541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
3231541Srgrimes			ptime += 7;
3248876Srgrimes
3251541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
3265651Sjoerg			cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_mtime,
3275651Sjoerg					    ISO_FTYPE_RRIP);
3281541Srgrimes			ptime += 7;
3291541Srgrimes		} else
3302806Sbde			bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec));
3318876Srgrimes
3321541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
3335651Sjoerg			cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_atime,
3345651Sjoerg					    ISO_FTYPE_RRIP);
3351541Srgrimes			ptime += 7;
3361541Srgrimes		} else
3371541Srgrimes			ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
3388876Srgrimes
3391541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
3405651Sjoerg			cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_ctime,
3415651Sjoerg					    ISO_FTYPE_RRIP);
3421541Srgrimes		else
3431541Srgrimes			ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
3448876Srgrimes
3451541Srgrimes	} else {
3461541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
3471541Srgrimes			ptime += 17;
3488876Srgrimes
3491541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
3501541Srgrimes			cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_mtime);
3511541Srgrimes			ptime += 17;
3521541Srgrimes		} else
3532806Sbde			bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec));
3548876Srgrimes
3551541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
3561541Srgrimes			cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_atime);
3571541Srgrimes			ptime += 17;
3581541Srgrimes		} else
3591541Srgrimes			ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
3608876Srgrimes
3611541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
3621541Srgrimes			cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_ctime);
3631541Srgrimes		else
3641541Srgrimes			ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
3658876Srgrimes
3661541Srgrimes	}
3671541Srgrimes	ana->fields &= ~ISO_SUSP_TSTAMP;
3681541Srgrimes	return ISO_SUSP_TSTAMP;
3691541Srgrimes}
3701541Srgrimes
3711541Srgrimesstatic void
3721541Srgrimescd9660_rrip_deftstamp(isodir,ana)
3731541Srgrimes	struct iso_directory_record  *isodir;
3741541Srgrimes	ISO_RRIP_ANALYZE *ana;
3751541Srgrimes{
3765651Sjoerg	cd9660_deftstamp(isodir,ana->inop,NULL,ISO_FTYPE_RRIP);
3771541Srgrimes}
3781541Srgrimes
3791541Srgrimes/*
3801541Srgrimes * POSIX device modes
3811541Srgrimes */
3821541Srgrimesstatic int
3831541Srgrimescd9660_rrip_device(p,ana)
3841541Srgrimes	ISO_RRIP_DEVICE *p;
3851541Srgrimes	ISO_RRIP_ANALYZE *ana;
3861541Srgrimes{
3871541Srgrimes	unsigned high, low;
3888876Srgrimes
3891541Srgrimes	high = isonum_733(p->dev_t_high_l);
3901541Srgrimes	low  = isonum_733(p->dev_t_low_l);
3918876Srgrimes
3921541Srgrimes	if ( high == 0 ) {
3931541Srgrimes		ana->inop->inode.iso_rdev = makedev( major(low), minor(low) );
3941541Srgrimes	} else {
3951541Srgrimes		ana->inop->inode.iso_rdev = makedev( high, minor(low) );
3961541Srgrimes	}
3971541Srgrimes	ana->fields &= ~ISO_SUSP_DEVICE;
3981541Srgrimes	return ISO_SUSP_DEVICE;
3991541Srgrimes}
4001541Srgrimes
4011541Srgrimes/*
4021541Srgrimes * Flag indicating
4031541Srgrimes */
4041541Srgrimesstatic int
4051541Srgrimescd9660_rrip_idflag(p,ana)
4061541Srgrimes	ISO_RRIP_IDFLAG *p;
4071541Srgrimes	ISO_RRIP_ANALYZE *ana;
4081541Srgrimes{
4091541Srgrimes	ana->fields &= isonum_711(p->flags)|~0xff; /* don't touch high bits */
4101541Srgrimes	/* special handling of RE field */
4111541Srgrimes	if (ana->fields&ISO_SUSP_RELDIR)
4121541Srgrimes		return cd9660_rrip_reldir(p,ana);
4138876Srgrimes
4141541Srgrimes	return ISO_SUSP_IDFLAG;
4151541Srgrimes}
4161541Srgrimes
4171541Srgrimes/*
4181541Srgrimes * Continuation pointer
4191541Srgrimes */
4201541Srgrimesstatic int
4211541Srgrimescd9660_rrip_cont(p,ana)
4221541Srgrimes	ISO_RRIP_CONT *p;
4231541Srgrimes	ISO_RRIP_ANALYZE *ana;
4241541Srgrimes{
4251541Srgrimes	ana->iso_ce_blk = isonum_733(p->location);
4261541Srgrimes	ana->iso_ce_off = isonum_733(p->offset);
4271541Srgrimes	ana->iso_ce_len = isonum_733(p->length);
4281541Srgrimes	return ISO_SUSP_CONT;
4291541Srgrimes}
4301541Srgrimes
4311541Srgrimes/*
4321541Srgrimes * System Use end
4331541Srgrimes */
4341541Srgrimesstatic int
4351541Srgrimescd9660_rrip_stop(p,ana)
4361541Srgrimes	ISO_SUSP_HEADER *p;
4371541Srgrimes	ISO_RRIP_ANALYZE *ana;
4381541Srgrimes{
4391541Srgrimes	/* stop analyzing */
4401541Srgrimes	ana->fields = 0;
4411541Srgrimes	return ISO_SUSP_STOP;
4421541Srgrimes}
4431541Srgrimes
4441541Srgrimes/*
4451541Srgrimes * Extension reference
4461541Srgrimes */
4471541Srgrimesstatic int
4481541Srgrimescd9660_rrip_extref(p,ana)
4491541Srgrimes	ISO_RRIP_EXTREF *p;
4501541Srgrimes	ISO_RRIP_ANALYZE *ana;
4511541Srgrimes{
4521541Srgrimes	if (isonum_711(p->len_id) != 10
4531541Srgrimes	    || bcmp((char *)p + 8,"RRIP_1991A",10)
4541541Srgrimes	    || isonum_711(p->version) != 1)
4551541Srgrimes		return 0;
4561541Srgrimes	ana->fields &= ~ISO_SUSP_EXTREF;
4571541Srgrimes	return ISO_SUSP_EXTREF;
4581541Srgrimes}
4591541Srgrimes
4601541Srgrimestypedef struct {
4611541Srgrimes	char type[2];
4621541Srgrimes	int (*func)();
4631541Srgrimes	void (*func2)();
4641541Srgrimes	int result;
4651541Srgrimes} RRIP_TABLE;
4661541Srgrimes
4671541Srgrimesstatic int
4681541Srgrimescd9660_rrip_loop(isodir,ana,table)
4691541Srgrimes	struct iso_directory_record *isodir;
4701541Srgrimes	ISO_RRIP_ANALYZE *ana;
4711541Srgrimes	RRIP_TABLE *table;
4721541Srgrimes{
4731541Srgrimes	register RRIP_TABLE *ptable;
4741541Srgrimes	register ISO_SUSP_HEADER *phead;
4751541Srgrimes	register ISO_SUSP_HEADER *pend;
4761541Srgrimes	struct buf *bp = NULL;
4771541Srgrimes	char *pwhead;
4781541Srgrimes	int result;
4798876Srgrimes
4801541Srgrimes	/*
4811541Srgrimes	 * Note: If name length is odd,
4825651Sjoerg	 *	 it will be padding 1 byte after the name
4831541Srgrimes	 */
4841541Srgrimes	pwhead = isodir->name + isonum_711(isodir->name_len);
4851541Srgrimes	if (!(isonum_711(isodir->name_len)&1))
4861541Srgrimes		pwhead++;
4878876Srgrimes
4881541Srgrimes	/* If it's not the '.' entry of the root dir obey SP field */
4891541Srgrimes	if (*isodir->name != 0
4901541Srgrimes	    || isonum_733(isodir->extent) != ana->imp->root_extent)
4911541Srgrimes		pwhead += ana->imp->rr_skip;
4921541Srgrimes	else
4931541Srgrimes		pwhead += ana->imp->rr_skip0;
4948876Srgrimes
4951541Srgrimes	phead = (ISO_SUSP_HEADER *)pwhead;
4961541Srgrimes	pend = (ISO_SUSP_HEADER *)((char *)isodir + isonum_711(isodir->length));
4978876Srgrimes
4981541Srgrimes	result = 0;
4991541Srgrimes	while (1) {
5001541Srgrimes		ana->iso_ce_len = 0;
5011541Srgrimes		/*
5021541Srgrimes		 * Note: "pend" should be more than one SUSP header
5038876Srgrimes		 */
5041541Srgrimes		while (pend >= phead + 1) {
5051541Srgrimes			if (isonum_711(phead->version) == 1) {
5061541Srgrimes				for (ptable = table; ptable->func; ptable++) {
5071541Srgrimes					if (*phead->type == *ptable->type
5081541Srgrimes					    && phead->type[1] == ptable->type[1]) {
5091541Srgrimes						result |= ptable->func(phead,ana);
5101541Srgrimes						break;
5111541Srgrimes					}
5121541Srgrimes				}
5131541Srgrimes				if (!ana->fields)
5141541Srgrimes					break;
5151541Srgrimes			}
5161541Srgrimes			/*
5171541Srgrimes			 * move to next SUSP
5181541Srgrimes			 * Hopefully this works with newer versions, too
5191541Srgrimes			 */
5201541Srgrimes			phead = (ISO_SUSP_HEADER *)((char *)phead + isonum_711(phead->length));
5211541Srgrimes		}
5228876Srgrimes
5231541Srgrimes		if ( ana->fields && ana->iso_ce_len ) {
5241541Srgrimes			if (ana->iso_ce_blk >= ana->imp->volume_space_size
5251541Srgrimes			    || ana->iso_ce_off + ana->iso_ce_len > ana->imp->logical_block_size
5261541Srgrimes			    || bread(ana->imp->im_devvp,
5272604Sdfr				     iso_lblktodaddr(ana->imp, ana->iso_ce_blk),
5281541Srgrimes				     ana->imp->logical_block_size,NOCRED,&bp))
5291541Srgrimes				/* what to do now? */
5301541Srgrimes				break;
5311541Srgrimes			phead = (ISO_SUSP_HEADER *)(bp->b_un.b_addr + ana->iso_ce_off);
5321541Srgrimes			pend = (ISO_SUSP_HEADER *) ((char *)phead + ana->iso_ce_len);
5331541Srgrimes		} else
5341541Srgrimes			break;
5351541Srgrimes	}
5361541Srgrimes	if (bp)
5371541Srgrimes		brelse(bp);
5381541Srgrimes	/*
5391541Srgrimes	 * If we don't find the Basic SUSP stuffs, just set default value
5401541Srgrimes	 *   ( attribute/time stamp )
5411541Srgrimes	 */
5421541Srgrimes	for (ptable = table; ptable->func2; ptable++)
5431541Srgrimes		if (!(ptable->result&result))
5441541Srgrimes			ptable->func2(isodir,ana);
5458876Srgrimes
5461541Srgrimes	return result;
5471541Srgrimes}
5481541Srgrimes
5491541Srgrimesstatic RRIP_TABLE rrip_table_analyze[] = {
5501541Srgrimes	{ "PX", cd9660_rrip_attr,	cd9660_rrip_defattr,	ISO_SUSP_ATTR },
5511541Srgrimes	{ "TF", cd9660_rrip_tstamp,	cd9660_rrip_deftstamp,	ISO_SUSP_TSTAMP },
5521541Srgrimes	{ "PN", cd9660_rrip_device,	0,			ISO_SUSP_DEVICE },
5531541Srgrimes	{ "RR", cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
5541541Srgrimes	{ "CE", cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
5551541Srgrimes	{ "ST", cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
5561541Srgrimes	{ "",	0,			0,			0 }
5571541Srgrimes};
5581541Srgrimes
5591541Srgrimesint
5601541Srgrimescd9660_rrip_analyze(isodir,inop,imp)
5611541Srgrimes	struct iso_directory_record *isodir;
5621541Srgrimes	struct iso_node *inop;
5631541Srgrimes	struct iso_mnt *imp;
5641541Srgrimes{
5651541Srgrimes	ISO_RRIP_ANALYZE analyze;
5668876Srgrimes
5671541Srgrimes	analyze.inop = inop;
5681541Srgrimes	analyze.imp = imp;
5691541Srgrimes	analyze.fields = ISO_SUSP_ATTR|ISO_SUSP_TSTAMP|ISO_SUSP_DEVICE;
5708876Srgrimes
5711541Srgrimes	return cd9660_rrip_loop(isodir,&analyze,rrip_table_analyze);
5721541Srgrimes}
5731541Srgrimes
5748876Srgrimes/*
5758876Srgrimes * Get Alternate Name from 'AL' record
5768876Srgrimes * If either no AL record or 0 length,
5771541Srgrimes *    it will be return the translated ISO9660 name,
5781541Srgrimes */
5791541Srgrimesstatic RRIP_TABLE rrip_table_getname[] = {
5801541Srgrimes	{ "NM", cd9660_rrip_altname,	cd9660_rrip_defname,	ISO_SUSP_ALTNAME },
5811541Srgrimes	{ "CL", cd9660_rrip_pclink,	0,			ISO_SUSP_CLINK|ISO_SUSP_PLINK },
5821541Srgrimes	{ "PL", cd9660_rrip_pclink,	0,			ISO_SUSP_CLINK|ISO_SUSP_PLINK },
5831541Srgrimes	{ "RE", cd9660_rrip_reldir,	0,			ISO_SUSP_RELDIR },
5841541Srgrimes	{ "RR", cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
5851541Srgrimes	{ "CE", cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
5861541Srgrimes	{ "ST", cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
5871541Srgrimes	{ "",	0,			0,			0 }
5881541Srgrimes};
5891541Srgrimes
5901541Srgrimesint
5911541Srgrimescd9660_rrip_getname(isodir,outbuf,outlen,inump,imp)
5921541Srgrimes	struct iso_directory_record *isodir;
5931541Srgrimes	char *outbuf;
5941541Srgrimes	u_short *outlen;
5951541Srgrimes	ino_t *inump;
5961541Srgrimes	struct iso_mnt *imp;
5971541Srgrimes{
5981541Srgrimes	ISO_RRIP_ANALYZE analyze;
5991541Srgrimes	RRIP_TABLE *tab;
6008876Srgrimes
6011541Srgrimes	analyze.outbuf = outbuf;
6021541Srgrimes	analyze.outlen = outlen;
6031541Srgrimes	analyze.maxlen = NAME_MAX;
6041541Srgrimes	analyze.inump = inump;
6051541Srgrimes	analyze.imp = imp;
6061541Srgrimes	analyze.fields = ISO_SUSP_ALTNAME|ISO_SUSP_RELDIR|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
6071541Srgrimes	*outlen = 0;
6088876Srgrimes
6091541Srgrimes	tab = rrip_table_getname;
6101541Srgrimes	if (*isodir->name == 0
6111541Srgrimes	    || *isodir->name == 1) {
6121541Srgrimes		cd9660_rrip_defname(isodir,&analyze);
6138876Srgrimes
6141541Srgrimes		analyze.fields &= ~ISO_SUSP_ALTNAME;
6151541Srgrimes		tab++;
6161541Srgrimes	}
6178876Srgrimes
6181541Srgrimes	return cd9660_rrip_loop(isodir,&analyze,tab);
6191541Srgrimes}
6201541Srgrimes
6218876Srgrimes/*
6228876Srgrimes * Get Symbolic Name from 'SL' record
6231541Srgrimes *
6241541Srgrimes * Note: isodir should contains SL record!
6251541Srgrimes */
6261541Srgrimesstatic RRIP_TABLE rrip_table_getsymname[] = {
6271541Srgrimes	{ "SL", cd9660_rrip_slink,	0,			ISO_SUSP_SLINK },
6281541Srgrimes	{ "RR", cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
6291541Srgrimes	{ "CE", cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
6301541Srgrimes	{ "ST", cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
6311541Srgrimes	{ "",	0,			0,			0 }
6321541Srgrimes};
6331541Srgrimes
6341541Srgrimesint
6351541Srgrimescd9660_rrip_getsymname(isodir,outbuf,outlen,imp)
6361541Srgrimes	struct iso_directory_record *isodir;
6371541Srgrimes	char *outbuf;
6381541Srgrimes	u_short *outlen;
6391541Srgrimes	struct iso_mnt *imp;
6401541Srgrimes{
6411541Srgrimes	ISO_RRIP_ANALYZE analyze;
6428876Srgrimes
6431541Srgrimes	analyze.outbuf = outbuf;
6441541Srgrimes	analyze.outlen = outlen;
6451541Srgrimes	*outlen = 0;
6461541Srgrimes	analyze.maxlen = MAXPATHLEN;
6471541Srgrimes	analyze.cont = 1;		/* don't start with a slash */
6481541Srgrimes	analyze.imp = imp;
6491541Srgrimes	analyze.fields = ISO_SUSP_SLINK;
6508876Srgrimes
6511541Srgrimes	return (cd9660_rrip_loop(isodir,&analyze,rrip_table_getsymname)&ISO_SUSP_SLINK);
6521541Srgrimes}
6531541Srgrimes
6541541Srgrimesstatic RRIP_TABLE rrip_table_extref[] = {
6551541Srgrimes	{ "ER", cd9660_rrip_extref,	0,			ISO_SUSP_EXTREF },
6561541Srgrimes	{ "CE", cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
6571541Srgrimes	{ "ST", cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
6581541Srgrimes	{ "",	0,			0,			0 }
6591541Srgrimes};
6601541Srgrimes
6611541Srgrimes/*
6621541Srgrimes * Check for Rock Ridge Extension and return offset of its fields.
6631541Srgrimes * Note: We require the ER field.
6641541Srgrimes */
6651541Srgrimesint
6661541Srgrimescd9660_rrip_offset(isodir,imp)
6671541Srgrimes	struct iso_directory_record *isodir;
6681541Srgrimes	struct iso_mnt *imp;
6691541Srgrimes{
6701541Srgrimes	ISO_RRIP_OFFSET *p;
6711541Srgrimes	ISO_RRIP_ANALYZE analyze;
6728876Srgrimes
6731541Srgrimes	imp->rr_skip0 = 0;
6741541Srgrimes	p = (ISO_RRIP_OFFSET *)(isodir->name + 1);
6751541Srgrimes	if (bcmp(p,"SP\7\1\276\357",6)) {
6761541Srgrimes		/* Maybe, it's a CDROM XA disc? */
6771541Srgrimes		imp->rr_skip0 = 15;
6781541Srgrimes		p = (ISO_RRIP_OFFSET *)((char *)p + 15);
6791541Srgrimes		if (bcmp(p,"SP\7\1\276\357",6))
6801541Srgrimes			return -1;
6811541Srgrimes	}
6828876Srgrimes
6831541Srgrimes	analyze.imp = imp;
6841541Srgrimes	analyze.fields = ISO_SUSP_EXTREF;
6851541Srgrimes	if (!(cd9660_rrip_loop(isodir,&analyze,rrip_table_extref)&ISO_SUSP_EXTREF))
6861541Srgrimes		return -1;
6878876Srgrimes
6881541Srgrimes	return isonum_711(p->skip);
6891541Srgrimes}
690