cd9660_rrip.c revision 187830
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 * 4. Neither the name of the University nor the names of its contributors
191541Srgrimes *    may be used to endorse or promote products derived from this software
201541Srgrimes *    without specific prior written permission.
211541Srgrimes *
221541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321541Srgrimes * SUCH DAMAGE.
331541Srgrimes *
3422521Sdyson *	@(#)cd9660_rrip.c	8.6 (Berkeley) 12/5/94
351541Srgrimes */
361541Srgrimes
37116181Sobrien#include <sys/cdefs.h>
38116181Sobrien__FBSDID("$FreeBSD: head/sys/fs/cd9660/cd9660_rrip.c 187830 2009-01-28 17:57:16Z ed $");
39116181Sobrien
401541Srgrimes#include <sys/param.h>
412806Sbde#include <sys/systm.h>
4260041Sphk#include <sys/bio.h>
431541Srgrimes#include <sys/buf.h>
441541Srgrimes#include <sys/vnode.h>
451541Srgrimes#include <sys/mount.h>
461541Srgrimes#include <sys/kernel.h>
47181803Sbz#include <sys/vimage.h>
481541Srgrimes
49166639Srodrigc#include <fs/cd9660/iso.h>
50166639Srodrigc#include <fs/cd9660/cd9660_node.h>
51166639Srodrigc#include <fs/cd9660/cd9660_rrip.h>
52166639Srodrigc#include <fs/cd9660/iso_rrip.h>
531541Srgrimes
5492765Salfredtypedef int	rrt_func_t(void *, ISO_RRIP_ANALYZE *ana);
5512597Sbde
5612597Sbdetypedef struct {
5712597Sbde	char type[2];
5812597Sbde	rrt_func_t *func;
5992765Salfred	void (*func2)(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana);
6012597Sbde	int result;
6112597Sbde} RRIP_TABLE;
6212597Sbde
6392765Salfredstatic int	cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, ISO_RRIP_ANALYZE *ana);
6492765Salfredstatic int	cd9660_rrip_attr(ISO_RRIP_ATTR *p, ISO_RRIP_ANALYZE *ana);
6592765Salfredstatic int	cd9660_rrip_cont(ISO_RRIP_CONT *p, ISO_RRIP_ANALYZE *ana);
6692765Salfredstatic void	cd9660_rrip_defattr(struct iso_directory_record *isodir,
6793075Sbde		    ISO_RRIP_ANALYZE *ana);
6892765Salfredstatic void	cd9660_rrip_defname(struct iso_directory_record *isodir,
6993075Sbde		    ISO_RRIP_ANALYZE *ana);
7092765Salfredstatic void	cd9660_rrip_deftstamp(struct iso_directory_record *isodir,
7193075Sbde		    ISO_RRIP_ANALYZE *ana);
7292765Salfredstatic int	cd9660_rrip_device(ISO_RRIP_DEVICE *p, ISO_RRIP_ANALYZE *ana);
7392765Salfredstatic int	cd9660_rrip_extref(ISO_RRIP_EXTREF *p, ISO_RRIP_ANALYZE *ana);
7492765Salfredstatic int	cd9660_rrip_idflag(ISO_RRIP_IDFLAG *p, ISO_RRIP_ANALYZE *ana);
7592765Salfredstatic int	cd9660_rrip_loop(struct iso_directory_record *isodir,
7693075Sbde		    ISO_RRIP_ANALYZE *ana, RRIP_TABLE *table);
7792765Salfredstatic int	cd9660_rrip_pclink(ISO_RRIP_CLINK *p, ISO_RRIP_ANALYZE *ana);
7892765Salfredstatic int	cd9660_rrip_reldir(ISO_RRIP_RELDIR *p, ISO_RRIP_ANALYZE *ana);
7992765Salfredstatic int	cd9660_rrip_slink(ISO_RRIP_SLINK *p, ISO_RRIP_ANALYZE *ana);
8092765Salfredstatic int	cd9660_rrip_stop(ISO_SUSP_HEADER *p, ISO_RRIP_ANALYZE *ana);
8192765Salfredstatic int	cd9660_rrip_tstamp(ISO_RRIP_TSTAMP *p, ISO_RRIP_ANALYZE *ana);
8212597Sbde
831541Srgrimes/*
841541Srgrimes * POSIX file attribute
851541Srgrimes */
861541Srgrimesstatic int
871541Srgrimescd9660_rrip_attr(p,ana)
881541Srgrimes	ISO_RRIP_ATTR *p;
891541Srgrimes	ISO_RRIP_ANALYZE *ana;
901541Srgrimes{
9122521Sdyson	ana->inop->inode.iso_mode = isonum_733(p->mode);
9222521Sdyson	ana->inop->inode.iso_uid = isonum_733(p->uid);
9322521Sdyson	ana->inop->inode.iso_gid = isonum_733(p->gid);
9422521Sdyson	ana->inop->inode.iso_links = isonum_733(p->links);
951541Srgrimes	ana->fields &= ~ISO_SUSP_ATTR;
961541Srgrimes	return ISO_SUSP_ATTR;
971541Srgrimes}
981541Srgrimes
991541Srgrimesstatic void
1001541Srgrimescd9660_rrip_defattr(isodir,ana)
1011541Srgrimes	struct iso_directory_record *isodir;
1021541Srgrimes	ISO_RRIP_ANALYZE *ana;
1031541Srgrimes{
1041541Srgrimes	/* But this is a required field! */
1051541Srgrimes	printf("RRIP without PX field?\n");
1065651Sjoerg	cd9660_defattr(isodir,ana->inop,NULL,ISO_FTYPE_RRIP);
1071541Srgrimes}
1081541Srgrimes
1091541Srgrimes/*
1101541Srgrimes * Symbolic Links
1111541Srgrimes */
1121541Srgrimesstatic int
1131541Srgrimescd9660_rrip_slink(p,ana)
1145651Sjoerg	ISO_RRIP_SLINK	*p;
1151541Srgrimes	ISO_RRIP_ANALYZE *ana;
1161541Srgrimes{
117183550Szec	INIT_VPROCG(TD_TO_VPROCG(curthread));
118131526Sphk	ISO_RRIP_SLINK_COMPONENT *pcomp;
119131526Sphk	ISO_RRIP_SLINK_COMPONENT *pcompe;
1201541Srgrimes	int len, wlen, cont;
1211541Srgrimes	char *outbuf, *inbuf;
1228876Srgrimes
1231541Srgrimes	pcomp = (ISO_RRIP_SLINK_COMPONENT *)p->component;
1241541Srgrimes	pcompe = (ISO_RRIP_SLINK_COMPONENT *)((char *)p + isonum_711(p->h.length));
1251541Srgrimes	len = *ana->outlen;
1261541Srgrimes	outbuf = ana->outbuf;
1271541Srgrimes	cont = ana->cont;
1288876Srgrimes
1291541Srgrimes	/*
1301541Srgrimes	 * Gathering a Symbolic name from each component with path
1311541Srgrimes	 */
1321541Srgrimes	for (;
1331541Srgrimes	     pcomp < pcompe;
1341541Srgrimes	     pcomp = (ISO_RRIP_SLINK_COMPONENT *)((char *)pcomp + ISO_RRIP_SLSIZ
1351541Srgrimes						  + isonum_711(pcomp->clen))) {
1368876Srgrimes
1371541Srgrimes		if (!cont) {
1381541Srgrimes			if (len < ana->maxlen) {
1391541Srgrimes				len++;
1401541Srgrimes				*outbuf++ = '/';
1411541Srgrimes			}
1421541Srgrimes		}
1431541Srgrimes		cont = 0;
1448876Srgrimes
1451541Srgrimes		inbuf = "..";
1461541Srgrimes		wlen = 0;
1478876Srgrimes
1481541Srgrimes		switch (*pcomp->cflag) {
1498876Srgrimes
1501541Srgrimes		case ISO_SUSP_CFLAG_CURRENT:
1511541Srgrimes			/* Inserting Current */
1521541Srgrimes			wlen = 1;
1531541Srgrimes			break;
1548876Srgrimes
1551541Srgrimes		case ISO_SUSP_CFLAG_PARENT:
1561541Srgrimes			/* Inserting Parent */
1571541Srgrimes			wlen = 2;
1581541Srgrimes			break;
1598876Srgrimes
1601541Srgrimes		case ISO_SUSP_CFLAG_ROOT:
1611541Srgrimes			/* Inserting slash for ROOT */
162156693Sjoerg			/* Double slash, nothing really to do here. */
1631541Srgrimes			break;
1648876Srgrimes
1651541Srgrimes		case ISO_SUSP_CFLAG_VOLROOT:
1661541Srgrimes			/* Inserting a mount point i.e. "/cdrom" */
1671541Srgrimes			/* same as above */
1681541Srgrimes			outbuf -= len;
1691541Srgrimes			len = 0;
1701541Srgrimes			inbuf = ana->imp->im_mountp->mnt_stat.f_mntonname;
1711541Srgrimes			wlen = strlen(inbuf);
1721541Srgrimes			break;
1738876Srgrimes
1741541Srgrimes		case ISO_SUSP_CFLAG_HOST:
175180291Srwatson			/* XXXRW: locking. */
1761541Srgrimes			/* Inserting hostname i.e. "kurt.tools.de" */
177181803Sbz			inbuf = V_hostname;
178181803Sbz			wlen = strlen(V_hostname);
1791541Srgrimes			break;
1808876Srgrimes
1811541Srgrimes		case ISO_SUSP_CFLAG_CONTINUE:
1821541Srgrimes			cont = 1;
183102412Scharnier			/* FALLTHROUGH */
1841541Srgrimes		case 0:
1851541Srgrimes			/* Inserting component */
1861541Srgrimes			wlen = isonum_711(pcomp->clen);
1871541Srgrimes			inbuf = pcomp->name;
1881541Srgrimes			break;
1891541Srgrimes		default:
1901541Srgrimes			printf("RRIP with incorrect flags?");
1911541Srgrimes			wlen = ana->maxlen + 1;
1921541Srgrimes			break;
1931541Srgrimes		}
1948876Srgrimes
1951541Srgrimes		if (len + wlen > ana->maxlen) {
1961541Srgrimes			/* indicate error to caller */
1971541Srgrimes			ana->cont = 1;
1981541Srgrimes			ana->fields = 0;
1991541Srgrimes			ana->outbuf -= *ana->outlen;
2001541Srgrimes			*ana->outlen = 0;
2011541Srgrimes			return 0;
2021541Srgrimes		}
2038876Srgrimes
2041541Srgrimes		bcopy(inbuf,outbuf,wlen);
2051541Srgrimes		outbuf += wlen;
2061541Srgrimes		len += wlen;
2078876Srgrimes
2081541Srgrimes	}
2091541Srgrimes	ana->outbuf = outbuf;
2101541Srgrimes	*ana->outlen = len;
2111541Srgrimes	ana->cont = cont;
2128876Srgrimes
2131541Srgrimes	if (!isonum_711(p->flags)) {
2141541Srgrimes		ana->fields &= ~ISO_SUSP_SLINK;
2151541Srgrimes		return ISO_SUSP_SLINK;
2161541Srgrimes	}
2171541Srgrimes	return 0;
2181541Srgrimes}
2191541Srgrimes
2201541Srgrimes/*
2211541Srgrimes * Alternate name
2221541Srgrimes */
2231541Srgrimesstatic int
2241541Srgrimescd9660_rrip_altname(p,ana)
2251541Srgrimes	ISO_RRIP_ALTNAME *p;
2261541Srgrimes	ISO_RRIP_ANALYZE *ana;
2271541Srgrimes{
228183550Szec	INIT_VPROCG(TD_TO_VPROCG(curthread));
2291541Srgrimes	char *inbuf;
2301541Srgrimes	int wlen;
2311541Srgrimes	int cont;
2328876Srgrimes
2331541Srgrimes	inbuf = "..";
2341541Srgrimes	wlen = 0;
2351541Srgrimes	cont = 0;
2368876Srgrimes
2371541Srgrimes	switch (*p->flags) {
2381541Srgrimes	case ISO_SUSP_CFLAG_CURRENT:
2391541Srgrimes		/* Inserting Current */
2401541Srgrimes		wlen = 1;
2411541Srgrimes		break;
2428876Srgrimes
2431541Srgrimes	case ISO_SUSP_CFLAG_PARENT:
2441541Srgrimes		/* Inserting Parent */
2451541Srgrimes		wlen = 2;
2461541Srgrimes		break;
2478876Srgrimes
2481541Srgrimes	case ISO_SUSP_CFLAG_HOST:
249180291Srwatson		/* XXXRW: locking. */
2501541Srgrimes		/* Inserting hostname i.e. "kurt.tools.de" */
251181803Sbz		inbuf = V_hostname;
252181803Sbz		wlen = strlen(V_hostname);
2531541Srgrimes		break;
2548876Srgrimes
2551541Srgrimes	case ISO_SUSP_CFLAG_CONTINUE:
2561541Srgrimes		cont = 1;
257102412Scharnier		/* FALLTHROUGH */
2581541Srgrimes	case 0:
2591541Srgrimes		/* Inserting component */
2601541Srgrimes		wlen = isonum_711(p->h.length) - 5;
2611541Srgrimes		inbuf = (char *)p + 5;
2621541Srgrimes		break;
2638876Srgrimes
2641541Srgrimes	default:
2651541Srgrimes		printf("RRIP with incorrect NM flags?\n");
2661541Srgrimes		wlen = ana->maxlen + 1;
2671541Srgrimes		break;
2681541Srgrimes	}
2698876Srgrimes
2701541Srgrimes	if ((*ana->outlen += wlen) > ana->maxlen) {
2711541Srgrimes		/* treat as no name field */
2721541Srgrimes		ana->fields &= ~ISO_SUSP_ALTNAME;
2731541Srgrimes		ana->outbuf -= *ana->outlen - wlen;
2741541Srgrimes		*ana->outlen = 0;
2751541Srgrimes		return 0;
2761541Srgrimes	}
2778876Srgrimes
2781541Srgrimes	bcopy(inbuf,ana->outbuf,wlen);
2791541Srgrimes	ana->outbuf += wlen;
2808876Srgrimes
2811541Srgrimes	if (!cont) {
2821541Srgrimes		ana->fields &= ~ISO_SUSP_ALTNAME;
2831541Srgrimes		return ISO_SUSP_ALTNAME;
2841541Srgrimes	}
2851541Srgrimes	return 0;
2861541Srgrimes}
2871541Srgrimes
2881541Srgrimesstatic void
2891541Srgrimescd9660_rrip_defname(isodir,ana)
2901541Srgrimes	struct iso_directory_record *isodir;
2911541Srgrimes	ISO_RRIP_ANALYZE *ana;
2921541Srgrimes{
29345773Sdcs	isofntrans(isodir->name,isonum_711(isodir->name_len),
29445773Sdcs		   ana->outbuf,ana->outlen,
295120492Sfjoe		   1,isonum_711(isodir->flags)&4, ana->imp->joliet_level,
296120492Sfjoe		   ana->imp->im_flags, ana->imp->im_d2l);
29745773Sdcs	switch (*ana->outbuf) {
2981541Srgrimes	default:
2991541Srgrimes		break;
3001541Srgrimes	case 1:
3011541Srgrimes		*ana->outlen = 2;
302102412Scharnier		/* FALLTHROUGH */
30345773Sdcs	case 0:
30445773Sdcs		/* outlen is 1 already */
30545773Sdcs		strcpy(ana->outbuf,"..");
3061541Srgrimes		break;
3071541Srgrimes	}
3081541Srgrimes}
3091541Srgrimes
3101541Srgrimes/*
3111541Srgrimes * Parent or Child Link
3121541Srgrimes */
3131541Srgrimesstatic int
3141541Srgrimescd9660_rrip_pclink(p,ana)
3155651Sjoerg	ISO_RRIP_CLINK	*p;
3161541Srgrimes	ISO_RRIP_ANALYZE *ana;
3171541Srgrimes{
3181541Srgrimes	*ana->inump = isonum_733(p->dir_loc) << ana->imp->im_bshift;
3191541Srgrimes	ana->fields &= ~(ISO_SUSP_CLINK|ISO_SUSP_PLINK);
3201541Srgrimes	return *p->h.type == 'C' ? ISO_SUSP_CLINK : ISO_SUSP_PLINK;
3211541Srgrimes}
3221541Srgrimes
3231541Srgrimes/*
3241541Srgrimes * Relocated directory
3251541Srgrimes */
3261541Srgrimesstatic int
3271541Srgrimescd9660_rrip_reldir(p,ana)
3285651Sjoerg	ISO_RRIP_RELDIR	 *p;
3291541Srgrimes	ISO_RRIP_ANALYZE *ana;
3301541Srgrimes{
3311541Srgrimes	/* special hack to make caller aware of RE field */
3321541Srgrimes	*ana->outlen = 0;
3331541Srgrimes	ana->fields = 0;
3341541Srgrimes	return ISO_SUSP_RELDIR|ISO_SUSP_ALTNAME|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
3351541Srgrimes}
3361541Srgrimes
3371541Srgrimesstatic int
3381541Srgrimescd9660_rrip_tstamp(p,ana)
3391541Srgrimes	ISO_RRIP_TSTAMP *p;
3401541Srgrimes	ISO_RRIP_ANALYZE *ana;
3411541Srgrimes{
34222521Sdyson	u_char *ptime;
343131526Sphk
3441541Srgrimes	ptime = p->time;
3458876Srgrimes
3461541Srgrimes	/* Check a format of time stamp (7bytes/17bytes) */
3471541Srgrimes	if (!(*p->flags&ISO_SUSP_TSTAMP_FORM17)) {
3481541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
3491541Srgrimes			ptime += 7;
3508876Srgrimes
3511541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
3525651Sjoerg			cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_mtime,
3535651Sjoerg					    ISO_FTYPE_RRIP);
3541541Srgrimes			ptime += 7;
3551541Srgrimes		} else
3562806Sbde			bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec));
357131526Sphk
3581541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
3595651Sjoerg			cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_atime,
3605651Sjoerg					    ISO_FTYPE_RRIP);
3611541Srgrimes			ptime += 7;
3621541Srgrimes		} else
3631541Srgrimes			ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
3648876Srgrimes
3651541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
3665651Sjoerg			cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_ctime,
3675651Sjoerg					    ISO_FTYPE_RRIP);
3681541Srgrimes		else
3691541Srgrimes			ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
3708876Srgrimes
3711541Srgrimes	} else {
3721541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_CREAT)
3731541Srgrimes			ptime += 17;
3748876Srgrimes
3751541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) {
3761541Srgrimes			cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_mtime);
3771541Srgrimes			ptime += 17;
3781541Srgrimes		} else
3792806Sbde			bzero(&ana->inop->inode.iso_mtime,sizeof(struct timespec));
380131526Sphk
3811541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) {
3821541Srgrimes			cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_atime);
3831541Srgrimes			ptime += 17;
3841541Srgrimes		} else
3851541Srgrimes			ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime;
3868876Srgrimes
3871541Srgrimes		if (*p->flags&ISO_SUSP_TSTAMP_ATTR)
3881541Srgrimes			cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_ctime);
3891541Srgrimes		else
3901541Srgrimes			ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime;
3918876Srgrimes
3921541Srgrimes	}
3931541Srgrimes	ana->fields &= ~ISO_SUSP_TSTAMP;
3941541Srgrimes	return ISO_SUSP_TSTAMP;
3951541Srgrimes}
3961541Srgrimes
3971541Srgrimesstatic void
3981541Srgrimescd9660_rrip_deftstamp(isodir,ana)
3991541Srgrimes	struct iso_directory_record  *isodir;
4001541Srgrimes	ISO_RRIP_ANALYZE *ana;
4011541Srgrimes{
4025651Sjoerg	cd9660_deftstamp(isodir,ana->inop,NULL,ISO_FTYPE_RRIP);
4031541Srgrimes}
4041541Srgrimes
4051541Srgrimes/*
4061541Srgrimes * POSIX device modes
4071541Srgrimes */
4081541Srgrimesstatic int
4091541Srgrimescd9660_rrip_device(p,ana)
4101541Srgrimes	ISO_RRIP_DEVICE *p;
4111541Srgrimes	ISO_RRIP_ANALYZE *ana;
4121541Srgrimes{
41322521Sdyson	u_int high, low;
414131526Sphk
41522521Sdyson	high = isonum_733(p->dev_t_high);
41622521Sdyson	low  = isonum_733(p->dev_t_low);
417131526Sphk
41822521Sdyson	if (high == 0)
419187830Sed		ana->inop->inode.iso_rdev = makedev(major(low), minor(low));
42022521Sdyson	else
421187830Sed		ana->inop->inode.iso_rdev = makedev(high, minor(low));
4221541Srgrimes	ana->fields &= ~ISO_SUSP_DEVICE;
4231541Srgrimes	return ISO_SUSP_DEVICE;
4241541Srgrimes}
4251541Srgrimes
4261541Srgrimes/*
4271541Srgrimes * Flag indicating
4281541Srgrimes */
4291541Srgrimesstatic int
4301541Srgrimescd9660_rrip_idflag(p,ana)
4311541Srgrimes	ISO_RRIP_IDFLAG *p;
4321541Srgrimes	ISO_RRIP_ANALYZE *ana;
4331541Srgrimes{
4341541Srgrimes	ana->fields &= isonum_711(p->flags)|~0xff; /* don't touch high bits */
4351541Srgrimes	/* special handling of RE field */
4361541Srgrimes	if (ana->fields&ISO_SUSP_RELDIR)
43712597Sbde		return cd9660_rrip_reldir(/* XXX */ (ISO_RRIP_RELDIR *)p,ana);
4388876Srgrimes
4391541Srgrimes	return ISO_SUSP_IDFLAG;
4401541Srgrimes}
4411541Srgrimes
4421541Srgrimes/*
4431541Srgrimes * Continuation pointer
4441541Srgrimes */
4451541Srgrimesstatic int
4461541Srgrimescd9660_rrip_cont(p,ana)
4471541Srgrimes	ISO_RRIP_CONT *p;
4481541Srgrimes	ISO_RRIP_ANALYZE *ana;
4491541Srgrimes{
4501541Srgrimes	ana->iso_ce_blk = isonum_733(p->location);
4511541Srgrimes	ana->iso_ce_off = isonum_733(p->offset);
4521541Srgrimes	ana->iso_ce_len = isonum_733(p->length);
4531541Srgrimes	return ISO_SUSP_CONT;
4541541Srgrimes}
4551541Srgrimes
4561541Srgrimes/*
4571541Srgrimes * System Use end
4581541Srgrimes */
4591541Srgrimesstatic int
4601541Srgrimescd9660_rrip_stop(p,ana)
4611541Srgrimes	ISO_SUSP_HEADER *p;
4621541Srgrimes	ISO_RRIP_ANALYZE *ana;
4631541Srgrimes{
4641541Srgrimes	return ISO_SUSP_STOP;
4651541Srgrimes}
4661541Srgrimes
4671541Srgrimes/*
4681541Srgrimes * Extension reference
4691541Srgrimes */
4701541Srgrimesstatic int
4711541Srgrimescd9660_rrip_extref(p,ana)
4721541Srgrimes	ISO_RRIP_EXTREF *p;
4731541Srgrimes	ISO_RRIP_ANALYZE *ana;
4741541Srgrimes{
475185334Slulf	if ( ! ((isonum_711(p->len_id) == 10
476185334Slulf	      && bcmp((char *)p + 8,"RRIP_1991A",10) == 0)
477185334Slulf	    || (isonum_711(p->len_id) == 10
478185334Slulf	      && bcmp((char *)p + 8,"IEEE_P1282",10) == 0)
479185334Slulf	    || (isonum_711(p->len_id) ==  9
480185334Slulf	      && bcmp((char *)p + 8,"IEEE_1282",  9) == 0))
4811541Srgrimes	    || isonum_711(p->version) != 1)
4821541Srgrimes		return 0;
4831541Srgrimes	ana->fields &= ~ISO_SUSP_EXTREF;
4841541Srgrimes	return ISO_SUSP_EXTREF;
4851541Srgrimes}
4861541Srgrimes
4871541Srgrimesstatic int
4881541Srgrimescd9660_rrip_loop(isodir,ana,table)
4891541Srgrimes	struct iso_directory_record *isodir;
4901541Srgrimes	ISO_RRIP_ANALYZE *ana;
4911541Srgrimes	RRIP_TABLE *table;
4921541Srgrimes{
493131526Sphk	RRIP_TABLE *ptable;
494131526Sphk	ISO_SUSP_HEADER *phead;
495131526Sphk	ISO_SUSP_HEADER *pend;
4961541Srgrimes	struct buf *bp = NULL;
4971541Srgrimes	char *pwhead;
498120492Sfjoe	u_short c;
4991541Srgrimes	int result;
5008876Srgrimes
5011541Srgrimes	/*
5021541Srgrimes	 * Note: If name length is odd,
5035651Sjoerg	 *	 it will be padding 1 byte after the name
5041541Srgrimes	 */
5051541Srgrimes	pwhead = isodir->name + isonum_711(isodir->name_len);
5061541Srgrimes	if (!(isonum_711(isodir->name_len)&1))
5071541Srgrimes		pwhead++;
508120492Sfjoe	isochar(isodir->name, pwhead, ana->imp->joliet_level, &c, NULL,
509120492Sfjoe		ana->imp->im_flags, ana->imp->im_d2l);
5108876Srgrimes
5111541Srgrimes	/* If it's not the '.' entry of the root dir obey SP field */
51245773Sdcs	if (c != 0 || isonum_733(isodir->extent) != ana->imp->root_extent)
5131541Srgrimes		pwhead += ana->imp->rr_skip;
5141541Srgrimes	else
5151541Srgrimes		pwhead += ana->imp->rr_skip0;
5168876Srgrimes
5171541Srgrimes	phead = (ISO_SUSP_HEADER *)pwhead;
5181541Srgrimes	pend = (ISO_SUSP_HEADER *)((char *)isodir + isonum_711(isodir->length));
5198876Srgrimes
5201541Srgrimes	result = 0;
5211541Srgrimes	while (1) {
5221541Srgrimes		ana->iso_ce_len = 0;
5231541Srgrimes		/*
5241541Srgrimes		 * Note: "pend" should be more than one SUSP header
5258876Srgrimes		 */
5261541Srgrimes		while (pend >= phead + 1) {
5271541Srgrimes			if (isonum_711(phead->version) == 1) {
5281541Srgrimes				for (ptable = table; ptable->func; ptable++) {
5291541Srgrimes					if (*phead->type == *ptable->type
5301541Srgrimes					    && phead->type[1] == ptable->type[1]) {
5311541Srgrimes						result |= ptable->func(phead,ana);
5321541Srgrimes						break;
5331541Srgrimes					}
5341541Srgrimes				}
5351541Srgrimes				if (!ana->fields)
5361541Srgrimes					break;
5371541Srgrimes			}
53822521Sdyson			if (result&ISO_SUSP_STOP) {
53922521Sdyson				result &= ~ISO_SUSP_STOP;
54022521Sdyson				break;
54122521Sdyson			}
54222521Sdyson			/* plausibility check */
54322521Sdyson			if (isonum_711(phead->length) < sizeof(*phead))
54422521Sdyson				break;
5451541Srgrimes			/*
5461541Srgrimes			 * move to next SUSP
5471541Srgrimes			 * Hopefully this works with newer versions, too
5481541Srgrimes			 */
5491541Srgrimes			phead = (ISO_SUSP_HEADER *)((char *)phead + isonum_711(phead->length));
5501541Srgrimes		}
551131526Sphk
55222521Sdyson		if (ana->fields && ana->iso_ce_len) {
5531541Srgrimes			if (ana->iso_ce_blk >= ana->imp->volume_space_size
5541541Srgrimes			    || ana->iso_ce_off + ana->iso_ce_len > ana->imp->logical_block_size
5551541Srgrimes			    || bread(ana->imp->im_devvp,
55622521Sdyson				     ana->iso_ce_blk <<
55722521Sdyson				     (ana->imp->im_bshift - DEV_BSHIFT),
55822521Sdyson				     ana->imp->logical_block_size, NOCRED, &bp))
5591541Srgrimes				/* what to do now? */
5601541Srgrimes				break;
56122521Sdyson			phead = (ISO_SUSP_HEADER *)(bp->b_data + ana->iso_ce_off);
5621541Srgrimes			pend = (ISO_SUSP_HEADER *) ((char *)phead + ana->iso_ce_len);
5631541Srgrimes		} else
5641541Srgrimes			break;
5651541Srgrimes	}
5661541Srgrimes	if (bp)
5671541Srgrimes		brelse(bp);
5681541Srgrimes	/*
5691541Srgrimes	 * If we don't find the Basic SUSP stuffs, just set default value
57022521Sdyson	 *   (attribute/time stamp)
5711541Srgrimes	 */
5721541Srgrimes	for (ptable = table; ptable->func2; ptable++)
5731541Srgrimes		if (!(ptable->result&result))
5741541Srgrimes			ptable->func2(isodir,ana);
5758876Srgrimes
5761541Srgrimes	return result;
5771541Srgrimes}
5781541Srgrimes
57912597Sbde/*
58022521Sdyson * Get Attributes.
58122521Sdyson */
58222521Sdyson/*
58312597Sbde * XXX the casts are bogus but will do for now.
58412597Sbde */
58512597Sbde#define	BC	(rrt_func_t *)
5861541Srgrimesstatic RRIP_TABLE rrip_table_analyze[] = {
58712597Sbde	{ "PX", BC cd9660_rrip_attr,	cd9660_rrip_defattr,	ISO_SUSP_ATTR },
58812597Sbde	{ "TF", BC cd9660_rrip_tstamp,	cd9660_rrip_deftstamp,	ISO_SUSP_TSTAMP },
58912597Sbde	{ "PN", BC cd9660_rrip_device,	0,			ISO_SUSP_DEVICE },
59012597Sbde	{ "RR", BC cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
59112597Sbde	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
59212597Sbde	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
5931541Srgrimes	{ "",	0,			0,			0 }
5941541Srgrimes};
5951541Srgrimes
5961541Srgrimesint
5971541Srgrimescd9660_rrip_analyze(isodir,inop,imp)
5981541Srgrimes	struct iso_directory_record *isodir;
5991541Srgrimes	struct iso_node *inop;
6001541Srgrimes	struct iso_mnt *imp;
6011541Srgrimes{
6021541Srgrimes	ISO_RRIP_ANALYZE analyze;
6038876Srgrimes
6041541Srgrimes	analyze.inop = inop;
6051541Srgrimes	analyze.imp = imp;
6061541Srgrimes	analyze.fields = ISO_SUSP_ATTR|ISO_SUSP_TSTAMP|ISO_SUSP_DEVICE;
6078876Srgrimes
6081541Srgrimes	return cd9660_rrip_loop(isodir,&analyze,rrip_table_analyze);
6091541Srgrimes}
6101541Srgrimes
611131526Sphk/*
61222521Sdyson * Get Alternate Name.
6131541Srgrimes */
6141541Srgrimesstatic RRIP_TABLE rrip_table_getname[] = {
61512597Sbde	{ "NM", BC cd9660_rrip_altname,	cd9660_rrip_defname,	ISO_SUSP_ALTNAME },
61612597Sbde	{ "CL", BC cd9660_rrip_pclink,	0,			ISO_SUSP_CLINK|ISO_SUSP_PLINK },
61712597Sbde	{ "PL", BC cd9660_rrip_pclink,	0,			ISO_SUSP_CLINK|ISO_SUSP_PLINK },
61812597Sbde	{ "RE", BC cd9660_rrip_reldir,	0,			ISO_SUSP_RELDIR },
61912597Sbde	{ "RR", BC cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
62012597Sbde	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
62112597Sbde	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
6221541Srgrimes	{ "",	0,			0,			0 }
6231541Srgrimes};
6241541Srgrimes
6251541Srgrimesint
6261541Srgrimescd9660_rrip_getname(isodir,outbuf,outlen,inump,imp)
6271541Srgrimes	struct iso_directory_record *isodir;
6281541Srgrimes	char *outbuf;
6291541Srgrimes	u_short *outlen;
6301541Srgrimes	ino_t *inump;
6311541Srgrimes	struct iso_mnt *imp;
6321541Srgrimes{
6331541Srgrimes	ISO_RRIP_ANALYZE analyze;
6341541Srgrimes	RRIP_TABLE *tab;
635120492Sfjoe	u_short c;
6368876Srgrimes
6371541Srgrimes	analyze.outbuf = outbuf;
6381541Srgrimes	analyze.outlen = outlen;
6391541Srgrimes	analyze.maxlen = NAME_MAX;
6401541Srgrimes	analyze.inump = inump;
6411541Srgrimes	analyze.imp = imp;
6421541Srgrimes	analyze.fields = ISO_SUSP_ALTNAME|ISO_SUSP_RELDIR|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
6431541Srgrimes	*outlen = 0;
6448876Srgrimes
64545773Sdcs	isochar(isodir->name, isodir->name + isonum_711(isodir->name_len),
646120492Sfjoe		imp->joliet_level, &c, NULL, imp->im_flags, imp->im_d2l);
6471541Srgrimes	tab = rrip_table_getname;
64845773Sdcs	if (c == 0 || c == 1) {
6491541Srgrimes		cd9660_rrip_defname(isodir,&analyze);
6508876Srgrimes
6511541Srgrimes		analyze.fields &= ~ISO_SUSP_ALTNAME;
6521541Srgrimes		tab++;
6531541Srgrimes	}
6548876Srgrimes
6551541Srgrimes	return cd9660_rrip_loop(isodir,&analyze,tab);
6561541Srgrimes}
6571541Srgrimes
658131526Sphk/*
65922521Sdyson * Get Symbolic Link.
6601541Srgrimes */
6611541Srgrimesstatic RRIP_TABLE rrip_table_getsymname[] = {
66212597Sbde	{ "SL", BC cd9660_rrip_slink,	0,			ISO_SUSP_SLINK },
66312597Sbde	{ "RR", BC cd9660_rrip_idflag,	0,			ISO_SUSP_IDFLAG },
66412597Sbde	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
66512597Sbde	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
6661541Srgrimes	{ "",	0,			0,			0 }
6671541Srgrimes};
6681541Srgrimes
6691541Srgrimesint
6701541Srgrimescd9660_rrip_getsymname(isodir,outbuf,outlen,imp)
6711541Srgrimes	struct iso_directory_record *isodir;
6721541Srgrimes	char *outbuf;
6731541Srgrimes	u_short *outlen;
6741541Srgrimes	struct iso_mnt *imp;
6751541Srgrimes{
6761541Srgrimes	ISO_RRIP_ANALYZE analyze;
6778876Srgrimes
6781541Srgrimes	analyze.outbuf = outbuf;
6791541Srgrimes	analyze.outlen = outlen;
6801541Srgrimes	*outlen = 0;
6811541Srgrimes	analyze.maxlen = MAXPATHLEN;
6821541Srgrimes	analyze.cont = 1;		/* don't start with a slash */
6831541Srgrimes	analyze.imp = imp;
6841541Srgrimes	analyze.fields = ISO_SUSP_SLINK;
6858876Srgrimes
6861541Srgrimes	return (cd9660_rrip_loop(isodir,&analyze,rrip_table_getsymname)&ISO_SUSP_SLINK);
6871541Srgrimes}
6881541Srgrimes
6891541Srgrimesstatic RRIP_TABLE rrip_table_extref[] = {
69012597Sbde	{ "ER", BC cd9660_rrip_extref,	0,			ISO_SUSP_EXTREF },
69112597Sbde	{ "CE", BC cd9660_rrip_cont,	0,			ISO_SUSP_CONT },
69212597Sbde	{ "ST", BC cd9660_rrip_stop,	0,			ISO_SUSP_STOP },
6931541Srgrimes	{ "",	0,			0,			0 }
6941541Srgrimes};
6951541Srgrimes
6961541Srgrimes/*
6971541Srgrimes * Check for Rock Ridge Extension and return offset of its fields.
69822521Sdyson * Note: We insist on the ER field.
6991541Srgrimes */
7001541Srgrimesint
7011541Srgrimescd9660_rrip_offset(isodir,imp)
7021541Srgrimes	struct iso_directory_record *isodir;
7031541Srgrimes	struct iso_mnt *imp;
7041541Srgrimes{
7051541Srgrimes	ISO_RRIP_OFFSET *p;
7061541Srgrimes	ISO_RRIP_ANALYZE analyze;
7078876Srgrimes
7081541Srgrimes	imp->rr_skip0 = 0;
7091541Srgrimes	p = (ISO_RRIP_OFFSET *)(isodir->name + 1);
7101541Srgrimes	if (bcmp(p,"SP\7\1\276\357",6)) {
7111541Srgrimes		/* Maybe, it's a CDROM XA disc? */
7121541Srgrimes		imp->rr_skip0 = 15;
7131541Srgrimes		p = (ISO_RRIP_OFFSET *)((char *)p + 15);
7141541Srgrimes		if (bcmp(p,"SP\7\1\276\357",6))
7151541Srgrimes			return -1;
7161541Srgrimes	}
7178876Srgrimes
7181541Srgrimes	analyze.imp = imp;
7191541Srgrimes	analyze.fields = ISO_SUSP_EXTREF;
7201541Srgrimes	if (!(cd9660_rrip_loop(isodir,&analyze,rrip_table_extref)&ISO_SUSP_EXTREF))
7211541Srgrimes		return -1;
7228876Srgrimes
7231541Srgrimes	return isonum_711(p->skip);
7241541Srgrimes}
725