xref: /titanic_53/usr/src/boot/lib/libstand/cd9660.c (revision 4a5d661a82b942b6538acd26209d959ce98b593a)
1*4a5d661aSToomas Soome /*	$NetBSD: cd9660.c,v 1.5 1997/06/26 19:11:33 drochner Exp $	*/
2*4a5d661aSToomas Soome 
3*4a5d661aSToomas Soome /*
4*4a5d661aSToomas Soome  * Copyright (C) 1996 Wolfgang Solfrank.
5*4a5d661aSToomas Soome  * Copyright (C) 1996 TooLs GmbH.
6*4a5d661aSToomas Soome  * All rights reserved.
7*4a5d661aSToomas Soome  *
8*4a5d661aSToomas Soome  * Redistribution and use in source and binary forms, with or without
9*4a5d661aSToomas Soome  * modification, are permitted provided that the following conditions
10*4a5d661aSToomas Soome  * are met:
11*4a5d661aSToomas Soome  * 1. Redistributions of source code must retain the above copyright
12*4a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer.
13*4a5d661aSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
14*4a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
15*4a5d661aSToomas Soome  *    documentation and/or other materials provided with the distribution.
16*4a5d661aSToomas Soome  * 3. All advertising materials mentioning features or use of this software
17*4a5d661aSToomas Soome  *    must display the following acknowledgement:
18*4a5d661aSToomas Soome  *	This product includes software developed by TooLs GmbH.
19*4a5d661aSToomas Soome  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20*4a5d661aSToomas Soome  *    derived from this software without specific prior written permission.
21*4a5d661aSToomas Soome  *
22*4a5d661aSToomas Soome  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23*4a5d661aSToomas Soome  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24*4a5d661aSToomas Soome  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25*4a5d661aSToomas Soome  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26*4a5d661aSToomas Soome  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27*4a5d661aSToomas Soome  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28*4a5d661aSToomas Soome  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29*4a5d661aSToomas Soome  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30*4a5d661aSToomas Soome  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31*4a5d661aSToomas Soome  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*4a5d661aSToomas Soome  */
33*4a5d661aSToomas Soome 
34*4a5d661aSToomas Soome #include <sys/cdefs.h>
35*4a5d661aSToomas Soome __FBSDID("$FreeBSD$");
36*4a5d661aSToomas Soome 
37*4a5d661aSToomas Soome /*
38*4a5d661aSToomas Soome  * Stand-alone ISO9660 file reading package.
39*4a5d661aSToomas Soome  *
40*4a5d661aSToomas Soome  * Note: This doesn't support Rock Ridge extensions, extended attributes,
41*4a5d661aSToomas Soome  * blocksizes other than 2048 bytes, multi-extent files, etc.
42*4a5d661aSToomas Soome  */
43*4a5d661aSToomas Soome #include <sys/param.h>
44*4a5d661aSToomas Soome #include <string.h>
45*4a5d661aSToomas Soome #include <sys/dirent.h>
46*4a5d661aSToomas Soome #include <isofs/cd9660/iso.h>
47*4a5d661aSToomas Soome #include <isofs/cd9660/cd9660_rrip.h>
48*4a5d661aSToomas Soome 
49*4a5d661aSToomas Soome #include "stand.h"
50*4a5d661aSToomas Soome 
51*4a5d661aSToomas Soome #define	SUSP_CONTINUATION	"CE"
52*4a5d661aSToomas Soome #define	SUSP_PRESENT		"SP"
53*4a5d661aSToomas Soome #define	SUSP_STOP		"ST"
54*4a5d661aSToomas Soome #define	SUSP_EXTREF		"ER"
55*4a5d661aSToomas Soome #define	RRIP_NAME		"NM"
56*4a5d661aSToomas Soome 
57*4a5d661aSToomas Soome typedef struct {
58*4a5d661aSToomas Soome 	ISO_SUSP_HEADER		h;
59*4a5d661aSToomas Soome 	u_char signature	[ISODCL (  5,    6)];
60*4a5d661aSToomas Soome 	u_char len_skp		[ISODCL (  7,    7)]; /* 711 */
61*4a5d661aSToomas Soome } ISO_SUSP_PRESENT;
62*4a5d661aSToomas Soome 
63*4a5d661aSToomas Soome static int	buf_read_file(struct open_file *f, char **buf_p,
64*4a5d661aSToomas Soome 		    size_t *size_p);
65*4a5d661aSToomas Soome static int	cd9660_open(const char *path, struct open_file *f);
66*4a5d661aSToomas Soome static int	cd9660_close(struct open_file *f);
67*4a5d661aSToomas Soome static int	cd9660_read(struct open_file *f, void *buf, size_t size,
68*4a5d661aSToomas Soome 		    size_t *resid);
69*4a5d661aSToomas Soome static int	cd9660_write(struct open_file *f, void *buf, size_t size,
70*4a5d661aSToomas Soome 		    size_t *resid);
71*4a5d661aSToomas Soome static off_t	cd9660_seek(struct open_file *f, off_t offset, int where);
72*4a5d661aSToomas Soome static int	cd9660_stat(struct open_file *f, struct stat *sb);
73*4a5d661aSToomas Soome static int	cd9660_readdir(struct open_file *f, struct dirent *d);
74*4a5d661aSToomas Soome static int	dirmatch(struct open_file *f, const char *path,
75*4a5d661aSToomas Soome 		    struct iso_directory_record *dp, int use_rrip, int lenskip);
76*4a5d661aSToomas Soome static int	rrip_check(struct open_file *f, struct iso_directory_record *dp,
77*4a5d661aSToomas Soome 		    int *lenskip);
78*4a5d661aSToomas Soome static char	*rrip_lookup_name(struct open_file *f,
79*4a5d661aSToomas Soome 		    struct iso_directory_record *dp, int lenskip, size_t *len);
80*4a5d661aSToomas Soome static ISO_SUSP_HEADER *susp_lookup_record(struct open_file *f,
81*4a5d661aSToomas Soome 		    const char *identifier, struct iso_directory_record *dp,
82*4a5d661aSToomas Soome 		    int lenskip);
83*4a5d661aSToomas Soome 
84*4a5d661aSToomas Soome struct fs_ops cd9660_fsops = {
85*4a5d661aSToomas Soome 	"cd9660",
86*4a5d661aSToomas Soome 	cd9660_open,
87*4a5d661aSToomas Soome 	cd9660_close,
88*4a5d661aSToomas Soome 	cd9660_read,
89*4a5d661aSToomas Soome 	cd9660_write,
90*4a5d661aSToomas Soome 	cd9660_seek,
91*4a5d661aSToomas Soome 	cd9660_stat,
92*4a5d661aSToomas Soome 	cd9660_readdir
93*4a5d661aSToomas Soome };
94*4a5d661aSToomas Soome 
95*4a5d661aSToomas Soome #define	F_ISDIR		0x0001		/* Directory */
96*4a5d661aSToomas Soome #define	F_ROOTDIR	0x0002		/* Root directory */
97*4a5d661aSToomas Soome #define	F_RR		0x0004		/* Rock Ridge on this volume */
98*4a5d661aSToomas Soome 
99*4a5d661aSToomas Soome struct file {
100*4a5d661aSToomas Soome 	int 		f_flags;	/* file flags */
101*4a5d661aSToomas Soome 	off_t 		f_off;		/* Current offset within file */
102*4a5d661aSToomas Soome 	daddr_t 	f_bno;		/* Starting block number */
103*4a5d661aSToomas Soome 	off_t 		f_size;		/* Size of file */
104*4a5d661aSToomas Soome 	daddr_t		f_buf_blkno;	/* block number of data block */
105*4a5d661aSToomas Soome 	char		*f_buf;		/* buffer for data block */
106*4a5d661aSToomas Soome 	int		f_susp_skip;	/* len_skip for SUSP records */
107*4a5d661aSToomas Soome };
108*4a5d661aSToomas Soome 
109*4a5d661aSToomas Soome struct ptable_ent {
110*4a5d661aSToomas Soome 	char namlen	[ISODCL( 1, 1)];	/* 711 */
111*4a5d661aSToomas Soome 	char extlen	[ISODCL( 2, 2)];	/* 711 */
112*4a5d661aSToomas Soome 	char block	[ISODCL( 3, 6)];	/* 732 */
113*4a5d661aSToomas Soome 	char parent	[ISODCL( 7, 8)];	/* 722 */
114*4a5d661aSToomas Soome 	char name	[1];
115*4a5d661aSToomas Soome };
116*4a5d661aSToomas Soome #define	PTFIXSZ		8
117*4a5d661aSToomas Soome #define	PTSIZE(pp)	roundup(PTFIXSZ + isonum_711((pp)->namlen), 2)
118*4a5d661aSToomas Soome 
119*4a5d661aSToomas Soome #define	cdb2devb(bno)	((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)
120*4a5d661aSToomas Soome 
121*4a5d661aSToomas Soome static ISO_SUSP_HEADER *
122*4a5d661aSToomas Soome susp_lookup_record(struct open_file *f, const char *identifier,
123*4a5d661aSToomas Soome     struct iso_directory_record *dp, int lenskip)
124*4a5d661aSToomas Soome {
125*4a5d661aSToomas Soome 	static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE];
126*4a5d661aSToomas Soome 	ISO_SUSP_HEADER *sh;
127*4a5d661aSToomas Soome 	ISO_RRIP_CONT *shc;
128*4a5d661aSToomas Soome 	char *p, *end;
129*4a5d661aSToomas Soome 	int error;
130*4a5d661aSToomas Soome 	size_t read;
131*4a5d661aSToomas Soome 
132*4a5d661aSToomas Soome 	p = dp->name + isonum_711(dp->name_len) + lenskip;
133*4a5d661aSToomas Soome 	/* Names of even length have a padding byte after the name. */
134*4a5d661aSToomas Soome 	if ((isonum_711(dp->name_len) & 1) == 0)
135*4a5d661aSToomas Soome 		p++;
136*4a5d661aSToomas Soome 	end = (char *)dp + isonum_711(dp->length);
137*4a5d661aSToomas Soome 	while (p + 3 < end) {
138*4a5d661aSToomas Soome 		sh = (ISO_SUSP_HEADER *)p;
139*4a5d661aSToomas Soome 		if (bcmp(sh->type, identifier, 2) == 0)
140*4a5d661aSToomas Soome 			return (sh);
141*4a5d661aSToomas Soome 		if (bcmp(sh->type, SUSP_STOP, 2) == 0)
142*4a5d661aSToomas Soome 			return (NULL);
143*4a5d661aSToomas Soome 		if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) {
144*4a5d661aSToomas Soome 			shc = (ISO_RRIP_CONT *)sh;
145*4a5d661aSToomas Soome 			error = f->f_dev->dv_strategy(f->f_devdata, F_READ,
146*4a5d661aSToomas Soome 			    cdb2devb(isonum_733(shc->location)), 0,
147*4a5d661aSToomas Soome 			    ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read);
148*4a5d661aSToomas Soome 
149*4a5d661aSToomas Soome 			/* Bail if it fails. */
150*4a5d661aSToomas Soome 			if (error != 0 || read != ISO_DEFAULT_BLOCK_SIZE)
151*4a5d661aSToomas Soome 				return (NULL);
152*4a5d661aSToomas Soome 			p = susp_buffer + isonum_733(shc->offset);
153*4a5d661aSToomas Soome 			end = p + isonum_733(shc->length);
154*4a5d661aSToomas Soome 		} else {
155*4a5d661aSToomas Soome 			/* Ignore this record and skip to the next. */
156*4a5d661aSToomas Soome 			p += isonum_711(sh->length);
157*4a5d661aSToomas Soome 
158*4a5d661aSToomas Soome 			/* Avoid infinite loops with corrupted file systems */
159*4a5d661aSToomas Soome 			if (isonum_711(sh->length) == 0)
160*4a5d661aSToomas Soome 				return (NULL);
161*4a5d661aSToomas Soome 		}
162*4a5d661aSToomas Soome 	}
163*4a5d661aSToomas Soome 	return (NULL);
164*4a5d661aSToomas Soome }
165*4a5d661aSToomas Soome 
166*4a5d661aSToomas Soome static char *
167*4a5d661aSToomas Soome rrip_lookup_name(struct open_file *f, struct iso_directory_record *dp,
168*4a5d661aSToomas Soome     int lenskip, size_t *len)
169*4a5d661aSToomas Soome {
170*4a5d661aSToomas Soome 	ISO_RRIP_ALTNAME *p;
171*4a5d661aSToomas Soome 
172*4a5d661aSToomas Soome 	if (len == NULL)
173*4a5d661aSToomas Soome 		return (NULL);
174*4a5d661aSToomas Soome 
175*4a5d661aSToomas Soome 	p = (ISO_RRIP_ALTNAME *)susp_lookup_record(f, RRIP_NAME, dp, lenskip);
176*4a5d661aSToomas Soome 	if (p == NULL)
177*4a5d661aSToomas Soome 		return (NULL);
178*4a5d661aSToomas Soome 	switch (*p->flags) {
179*4a5d661aSToomas Soome 	case ISO_SUSP_CFLAG_CURRENT:
180*4a5d661aSToomas Soome 		*len = 1;
181*4a5d661aSToomas Soome 		return (".");
182*4a5d661aSToomas Soome 	case ISO_SUSP_CFLAG_PARENT:
183*4a5d661aSToomas Soome 		*len = 2;
184*4a5d661aSToomas Soome 		return ("..");
185*4a5d661aSToomas Soome 	case 0:
186*4a5d661aSToomas Soome 		*len = isonum_711(p->h.length) - 5;
187*4a5d661aSToomas Soome 		return ((char *)p + 5);
188*4a5d661aSToomas Soome 	default:
189*4a5d661aSToomas Soome 		/*
190*4a5d661aSToomas Soome 		 * We don't handle hostnames or continued names as they are
191*4a5d661aSToomas Soome 		 * too hard, so just bail and use the default name.
192*4a5d661aSToomas Soome 		 */
193*4a5d661aSToomas Soome 		return (NULL);
194*4a5d661aSToomas Soome 	}
195*4a5d661aSToomas Soome }
196*4a5d661aSToomas Soome 
197*4a5d661aSToomas Soome static int
198*4a5d661aSToomas Soome rrip_check(struct open_file *f, struct iso_directory_record *dp, int *lenskip)
199*4a5d661aSToomas Soome {
200*4a5d661aSToomas Soome 	ISO_SUSP_PRESENT *sp;
201*4a5d661aSToomas Soome 	ISO_RRIP_EXTREF *er;
202*4a5d661aSToomas Soome 	char *p;
203*4a5d661aSToomas Soome 
204*4a5d661aSToomas Soome 	/* First, see if we can find a SP field. */
205*4a5d661aSToomas Soome 	p = dp->name + isonum_711(dp->name_len);
206*4a5d661aSToomas Soome 	if (p > (char *)dp + isonum_711(dp->length))
207*4a5d661aSToomas Soome 		return (0);
208*4a5d661aSToomas Soome 	sp = (ISO_SUSP_PRESENT *)p;
209*4a5d661aSToomas Soome 	if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0)
210*4a5d661aSToomas Soome 		return (0);
211*4a5d661aSToomas Soome 	if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT))
212*4a5d661aSToomas Soome 		return (0);
213*4a5d661aSToomas Soome 	if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef)
214*4a5d661aSToomas Soome 		return (0);
215*4a5d661aSToomas Soome 	*lenskip = isonum_711(sp->len_skp);
216*4a5d661aSToomas Soome 
217*4a5d661aSToomas Soome 	/*
218*4a5d661aSToomas Soome 	 * Now look for an ER field.  If RRIP is present, then there must
219*4a5d661aSToomas Soome 	 * be at least one of these.  It would be more pedantic to walk
220*4a5d661aSToomas Soome 	 * through the list of fields looking for a Rock Ridge ER field.
221*4a5d661aSToomas Soome 	 */
222*4a5d661aSToomas Soome 	er = (ISO_RRIP_EXTREF *)susp_lookup_record(f, SUSP_EXTREF, dp, 0);
223*4a5d661aSToomas Soome 	if (er == NULL)
224*4a5d661aSToomas Soome 		return (0);
225*4a5d661aSToomas Soome 	return (1);
226*4a5d661aSToomas Soome }
227*4a5d661aSToomas Soome 
228*4a5d661aSToomas Soome static int
229*4a5d661aSToomas Soome dirmatch(struct open_file *f, const char *path, struct iso_directory_record *dp,
230*4a5d661aSToomas Soome     int use_rrip, int lenskip)
231*4a5d661aSToomas Soome {
232*4a5d661aSToomas Soome 	size_t len;
233*4a5d661aSToomas Soome 	char *cp;
234*4a5d661aSToomas Soome 	int i, icase;
235*4a5d661aSToomas Soome 
236*4a5d661aSToomas Soome 	if (use_rrip)
237*4a5d661aSToomas Soome 		cp = rrip_lookup_name(f, dp, lenskip, &len);
238*4a5d661aSToomas Soome 	else
239*4a5d661aSToomas Soome 		cp = NULL;
240*4a5d661aSToomas Soome 	if (cp == NULL) {
241*4a5d661aSToomas Soome 		len = isonum_711(dp->name_len);
242*4a5d661aSToomas Soome 		cp = dp->name;
243*4a5d661aSToomas Soome 		icase = 1;
244*4a5d661aSToomas Soome 	} else
245*4a5d661aSToomas Soome 		icase = 0;
246*4a5d661aSToomas Soome 	for (i = len; --i >= 0; path++, cp++) {
247*4a5d661aSToomas Soome 		if (!*path || *path == '/')
248*4a5d661aSToomas Soome 			break;
249*4a5d661aSToomas Soome 		if (*path == *cp)
250*4a5d661aSToomas Soome 			continue;
251*4a5d661aSToomas Soome 		if (!icase && toupper(*path) == *cp)
252*4a5d661aSToomas Soome 			continue;
253*4a5d661aSToomas Soome 		return 0;
254*4a5d661aSToomas Soome 	}
255*4a5d661aSToomas Soome 	if (*path && *path != '/')
256*4a5d661aSToomas Soome 		return 0;
257*4a5d661aSToomas Soome 	/*
258*4a5d661aSToomas Soome 	 * Allow stripping of trailing dots and the version number.
259*4a5d661aSToomas Soome 	 * Note that this will find the first instead of the last version
260*4a5d661aSToomas Soome 	 * of a file.
261*4a5d661aSToomas Soome 	 */
262*4a5d661aSToomas Soome 	if (i >= 0 && (*cp == ';' || *cp == '.')) {
263*4a5d661aSToomas Soome 		/* This is to prevent matching of numeric extensions */
264*4a5d661aSToomas Soome 		if (*cp == '.' && cp[1] != ';')
265*4a5d661aSToomas Soome 			return 0;
266*4a5d661aSToomas Soome 		while (--i >= 0)
267*4a5d661aSToomas Soome 			if (*++cp != ';' && (*cp < '0' || *cp > '9'))
268*4a5d661aSToomas Soome 				return 0;
269*4a5d661aSToomas Soome 	}
270*4a5d661aSToomas Soome 	return 1;
271*4a5d661aSToomas Soome }
272*4a5d661aSToomas Soome 
273*4a5d661aSToomas Soome static int
274*4a5d661aSToomas Soome cd9660_open(const char *path, struct open_file *f)
275*4a5d661aSToomas Soome {
276*4a5d661aSToomas Soome 	struct file *fp = 0;
277*4a5d661aSToomas Soome 	void *buf;
278*4a5d661aSToomas Soome 	struct iso_primary_descriptor *vd;
279*4a5d661aSToomas Soome 	size_t buf_size, read, dsize, off;
280*4a5d661aSToomas Soome 	daddr_t bno, boff;
281*4a5d661aSToomas Soome 	struct iso_directory_record rec;
282*4a5d661aSToomas Soome 	struct iso_directory_record *dp = 0;
283*4a5d661aSToomas Soome 	int rc, first, use_rrip, lenskip;
284*4a5d661aSToomas Soome 
285*4a5d661aSToomas Soome 	/* First find the volume descriptor */
286*4a5d661aSToomas Soome 	buf = malloc(buf_size = ISO_DEFAULT_BLOCK_SIZE);
287*4a5d661aSToomas Soome 	vd = buf;
288*4a5d661aSToomas Soome 	for (bno = 16;; bno++) {
289*4a5d661aSToomas Soome 		twiddle(1);
290*4a5d661aSToomas Soome 		rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
291*4a5d661aSToomas Soome 		    0, ISO_DEFAULT_BLOCK_SIZE, buf, &read);
292*4a5d661aSToomas Soome 		if (rc)
293*4a5d661aSToomas Soome 			goto out;
294*4a5d661aSToomas Soome 		if (read != ISO_DEFAULT_BLOCK_SIZE) {
295*4a5d661aSToomas Soome 			rc = EIO;
296*4a5d661aSToomas Soome 			goto out;
297*4a5d661aSToomas Soome 		}
298*4a5d661aSToomas Soome 		rc = EINVAL;
299*4a5d661aSToomas Soome 		if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0)
300*4a5d661aSToomas Soome 			goto out;
301*4a5d661aSToomas Soome 		if (isonum_711(vd->type) == ISO_VD_END)
302*4a5d661aSToomas Soome 			goto out;
303*4a5d661aSToomas Soome 		if (isonum_711(vd->type) == ISO_VD_PRIMARY)
304*4a5d661aSToomas Soome 			break;
305*4a5d661aSToomas Soome 	}
306*4a5d661aSToomas Soome 	if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE)
307*4a5d661aSToomas Soome 		goto out;
308*4a5d661aSToomas Soome 
309*4a5d661aSToomas Soome 	rec = *(struct iso_directory_record *) vd->root_directory_record;
310*4a5d661aSToomas Soome 	if (*path == '/') path++; /* eat leading '/' */
311*4a5d661aSToomas Soome 
312*4a5d661aSToomas Soome 	first = 1;
313*4a5d661aSToomas Soome 	use_rrip = 0;
314*4a5d661aSToomas Soome 	while (*path) {
315*4a5d661aSToomas Soome 		bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
316*4a5d661aSToomas Soome 		dsize = isonum_733(rec.size);
317*4a5d661aSToomas Soome 		off = 0;
318*4a5d661aSToomas Soome 		boff = 0;
319*4a5d661aSToomas Soome 
320*4a5d661aSToomas Soome 		while (off < dsize) {
321*4a5d661aSToomas Soome 			if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) {
322*4a5d661aSToomas Soome 				twiddle(1);
323*4a5d661aSToomas Soome 				rc = f->f_dev->dv_strategy
324*4a5d661aSToomas Soome 					(f->f_devdata, F_READ,
325*4a5d661aSToomas Soome 					 cdb2devb(bno + boff),
326*4a5d661aSToomas Soome 					 0, ISO_DEFAULT_BLOCK_SIZE,
327*4a5d661aSToomas Soome 					 buf, &read);
328*4a5d661aSToomas Soome 				if (rc)
329*4a5d661aSToomas Soome 					goto out;
330*4a5d661aSToomas Soome 				if (read != ISO_DEFAULT_BLOCK_SIZE) {
331*4a5d661aSToomas Soome 					rc = EIO;
332*4a5d661aSToomas Soome 					goto out;
333*4a5d661aSToomas Soome 				}
334*4a5d661aSToomas Soome 				boff++;
335*4a5d661aSToomas Soome 				dp = (struct iso_directory_record *) buf;
336*4a5d661aSToomas Soome 			}
337*4a5d661aSToomas Soome 			if (isonum_711(dp->length) == 0) {
338*4a5d661aSToomas Soome 			    /* skip to next block, if any */
339*4a5d661aSToomas Soome 			    off = boff * ISO_DEFAULT_BLOCK_SIZE;
340*4a5d661aSToomas Soome 			    continue;
341*4a5d661aSToomas Soome 			}
342*4a5d661aSToomas Soome 
343*4a5d661aSToomas Soome 			/* See if RRIP is in use. */
344*4a5d661aSToomas Soome 			if (first)
345*4a5d661aSToomas Soome 				use_rrip = rrip_check(f, dp, &lenskip);
346*4a5d661aSToomas Soome 
347*4a5d661aSToomas Soome 			if (dirmatch(f, path, dp, use_rrip,
348*4a5d661aSToomas Soome 				first ? 0 : lenskip)) {
349*4a5d661aSToomas Soome 				first = 0;
350*4a5d661aSToomas Soome 				break;
351*4a5d661aSToomas Soome 			} else
352*4a5d661aSToomas Soome 				first = 0;
353*4a5d661aSToomas Soome 
354*4a5d661aSToomas Soome 			dp = (struct iso_directory_record *)
355*4a5d661aSToomas Soome 				((char *) dp + isonum_711(dp->length));
356*4a5d661aSToomas Soome 			off += isonum_711(dp->length);
357*4a5d661aSToomas Soome 		}
358*4a5d661aSToomas Soome 		if (off >= dsize) {
359*4a5d661aSToomas Soome 			rc = ENOENT;
360*4a5d661aSToomas Soome 			goto out;
361*4a5d661aSToomas Soome 		}
362*4a5d661aSToomas Soome 
363*4a5d661aSToomas Soome 		rec = *dp;
364*4a5d661aSToomas Soome 		while (*path && *path != '/') /* look for next component */
365*4a5d661aSToomas Soome 			path++;
366*4a5d661aSToomas Soome 		if (*path) path++; /* skip '/' */
367*4a5d661aSToomas Soome 	}
368*4a5d661aSToomas Soome 
369*4a5d661aSToomas Soome 	/* allocate file system specific data structure */
370*4a5d661aSToomas Soome 	fp = malloc(sizeof(struct file));
371*4a5d661aSToomas Soome 	bzero(fp, sizeof(struct file));
372*4a5d661aSToomas Soome 	f->f_fsdata = (void *)fp;
373*4a5d661aSToomas Soome 
374*4a5d661aSToomas Soome 	if ((isonum_711(rec.flags) & 2) != 0) {
375*4a5d661aSToomas Soome 		fp->f_flags = F_ISDIR;
376*4a5d661aSToomas Soome 	}
377*4a5d661aSToomas Soome 	if (first) {
378*4a5d661aSToomas Soome 		fp->f_flags |= F_ROOTDIR;
379*4a5d661aSToomas Soome 
380*4a5d661aSToomas Soome 		/* Check for Rock Ridge since we didn't in the loop above. */
381*4a5d661aSToomas Soome 		bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
382*4a5d661aSToomas Soome 		twiddle(1);
383*4a5d661aSToomas Soome 		rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno),
384*4a5d661aSToomas Soome 		    0, ISO_DEFAULT_BLOCK_SIZE, buf, &read);
385*4a5d661aSToomas Soome 		if (rc)
386*4a5d661aSToomas Soome 			goto out;
387*4a5d661aSToomas Soome 		if (read != ISO_DEFAULT_BLOCK_SIZE) {
388*4a5d661aSToomas Soome 			rc = EIO;
389*4a5d661aSToomas Soome 			goto out;
390*4a5d661aSToomas Soome 		}
391*4a5d661aSToomas Soome 		dp = (struct iso_directory_record *)buf;
392*4a5d661aSToomas Soome 		use_rrip = rrip_check(f, dp, &lenskip);
393*4a5d661aSToomas Soome 	}
394*4a5d661aSToomas Soome 	if (use_rrip) {
395*4a5d661aSToomas Soome 		fp->f_flags |= F_RR;
396*4a5d661aSToomas Soome 		fp->f_susp_skip = lenskip;
397*4a5d661aSToomas Soome 	}
398*4a5d661aSToomas Soome 	fp->f_off = 0;
399*4a5d661aSToomas Soome 	fp->f_bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
400*4a5d661aSToomas Soome 	fp->f_size = isonum_733(rec.size);
401*4a5d661aSToomas Soome 	free(buf);
402*4a5d661aSToomas Soome 
403*4a5d661aSToomas Soome 	return 0;
404*4a5d661aSToomas Soome 
405*4a5d661aSToomas Soome out:
406*4a5d661aSToomas Soome 	if (fp)
407*4a5d661aSToomas Soome 		free(fp);
408*4a5d661aSToomas Soome 	free(buf);
409*4a5d661aSToomas Soome 
410*4a5d661aSToomas Soome 	return rc;
411*4a5d661aSToomas Soome }
412*4a5d661aSToomas Soome 
413*4a5d661aSToomas Soome static int
414*4a5d661aSToomas Soome cd9660_close(struct open_file *f)
415*4a5d661aSToomas Soome {
416*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
417*4a5d661aSToomas Soome 
418*4a5d661aSToomas Soome 	f->f_fsdata = 0;
419*4a5d661aSToomas Soome 	free(fp);
420*4a5d661aSToomas Soome 
421*4a5d661aSToomas Soome 	return 0;
422*4a5d661aSToomas Soome }
423*4a5d661aSToomas Soome 
424*4a5d661aSToomas Soome static int
425*4a5d661aSToomas Soome buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
426*4a5d661aSToomas Soome {
427*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
428*4a5d661aSToomas Soome 	daddr_t blkno, blkoff;
429*4a5d661aSToomas Soome 	int rc = 0;
430*4a5d661aSToomas Soome 	size_t read;
431*4a5d661aSToomas Soome 
432*4a5d661aSToomas Soome 	blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE + fp->f_bno;
433*4a5d661aSToomas Soome 	blkoff = fp->f_off % ISO_DEFAULT_BLOCK_SIZE;
434*4a5d661aSToomas Soome 
435*4a5d661aSToomas Soome 	if (blkno != fp->f_buf_blkno) {
436*4a5d661aSToomas Soome 		if (fp->f_buf == (char *)0)
437*4a5d661aSToomas Soome 			fp->f_buf = malloc(ISO_DEFAULT_BLOCK_SIZE);
438*4a5d661aSToomas Soome 
439*4a5d661aSToomas Soome 		twiddle(16);
440*4a5d661aSToomas Soome 		rc = f->f_dev->dv_strategy(f->f_devdata, F_READ,
441*4a5d661aSToomas Soome 		    cdb2devb(blkno), 0, ISO_DEFAULT_BLOCK_SIZE,
442*4a5d661aSToomas Soome 		    fp->f_buf, &read);
443*4a5d661aSToomas Soome 		if (rc)
444*4a5d661aSToomas Soome 			return (rc);
445*4a5d661aSToomas Soome 		if (read != ISO_DEFAULT_BLOCK_SIZE)
446*4a5d661aSToomas Soome 			return (EIO);
447*4a5d661aSToomas Soome 
448*4a5d661aSToomas Soome 		fp->f_buf_blkno = blkno;
449*4a5d661aSToomas Soome 	}
450*4a5d661aSToomas Soome 
451*4a5d661aSToomas Soome 	*buf_p = fp->f_buf + blkoff;
452*4a5d661aSToomas Soome 	*size_p = ISO_DEFAULT_BLOCK_SIZE - blkoff;
453*4a5d661aSToomas Soome 
454*4a5d661aSToomas Soome 	if (*size_p > fp->f_size - fp->f_off)
455*4a5d661aSToomas Soome 		*size_p = fp->f_size - fp->f_off;
456*4a5d661aSToomas Soome 	return (rc);
457*4a5d661aSToomas Soome }
458*4a5d661aSToomas Soome 
459*4a5d661aSToomas Soome static int
460*4a5d661aSToomas Soome cd9660_read(struct open_file *f, void *start, size_t size, size_t *resid)
461*4a5d661aSToomas Soome {
462*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
463*4a5d661aSToomas Soome 	char *buf, *addr;
464*4a5d661aSToomas Soome 	size_t buf_size, csize;
465*4a5d661aSToomas Soome 	int rc = 0;
466*4a5d661aSToomas Soome 
467*4a5d661aSToomas Soome 	addr = start;
468*4a5d661aSToomas Soome 	while (size) {
469*4a5d661aSToomas Soome 		if (fp->f_off < 0 || fp->f_off >= fp->f_size)
470*4a5d661aSToomas Soome 			break;
471*4a5d661aSToomas Soome 
472*4a5d661aSToomas Soome 		rc = buf_read_file(f, &buf, &buf_size);
473*4a5d661aSToomas Soome 		if (rc)
474*4a5d661aSToomas Soome 			break;
475*4a5d661aSToomas Soome 
476*4a5d661aSToomas Soome 		csize = size > buf_size ? buf_size : size;
477*4a5d661aSToomas Soome 		bcopy(buf, addr, csize);
478*4a5d661aSToomas Soome 
479*4a5d661aSToomas Soome 		fp->f_off += csize;
480*4a5d661aSToomas Soome 		addr += csize;
481*4a5d661aSToomas Soome 		size -= csize;
482*4a5d661aSToomas Soome 	}
483*4a5d661aSToomas Soome 	if (resid)
484*4a5d661aSToomas Soome 		*resid = size;
485*4a5d661aSToomas Soome 	return (rc);
486*4a5d661aSToomas Soome }
487*4a5d661aSToomas Soome 
488*4a5d661aSToomas Soome static int
489*4a5d661aSToomas Soome cd9660_readdir(struct open_file *f, struct dirent *d)
490*4a5d661aSToomas Soome {
491*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
492*4a5d661aSToomas Soome 	struct iso_directory_record *ep;
493*4a5d661aSToomas Soome 	size_t buf_size, reclen, namelen;
494*4a5d661aSToomas Soome 	int error = 0;
495*4a5d661aSToomas Soome 	int lenskip;
496*4a5d661aSToomas Soome 	char *buf, *name;
497*4a5d661aSToomas Soome 
498*4a5d661aSToomas Soome again:
499*4a5d661aSToomas Soome 	if (fp->f_off >= fp->f_size)
500*4a5d661aSToomas Soome 		return (ENOENT);
501*4a5d661aSToomas Soome 	error = buf_read_file(f, &buf, &buf_size);
502*4a5d661aSToomas Soome 	if (error)
503*4a5d661aSToomas Soome 		return (error);
504*4a5d661aSToomas Soome 	ep = (struct iso_directory_record *)buf;
505*4a5d661aSToomas Soome 
506*4a5d661aSToomas Soome 	if (isonum_711(ep->length) == 0) {
507*4a5d661aSToomas Soome 		daddr_t blkno;
508*4a5d661aSToomas Soome 
509*4a5d661aSToomas Soome 		/* skip to next block, if any */
510*4a5d661aSToomas Soome 		blkno = fp->f_off / ISO_DEFAULT_BLOCK_SIZE;
511*4a5d661aSToomas Soome 		fp->f_off = (blkno + 1) * ISO_DEFAULT_BLOCK_SIZE;
512*4a5d661aSToomas Soome 		goto again;
513*4a5d661aSToomas Soome 	}
514*4a5d661aSToomas Soome 
515*4a5d661aSToomas Soome 	if (fp->f_flags & F_RR) {
516*4a5d661aSToomas Soome 		if (fp->f_flags & F_ROOTDIR && fp->f_off == 0)
517*4a5d661aSToomas Soome 			lenskip = 0;
518*4a5d661aSToomas Soome 		else
519*4a5d661aSToomas Soome 			lenskip = fp->f_susp_skip;
520*4a5d661aSToomas Soome 		name = rrip_lookup_name(f, ep, lenskip, &namelen);
521*4a5d661aSToomas Soome 	} else
522*4a5d661aSToomas Soome 		name = NULL;
523*4a5d661aSToomas Soome 	if (name == NULL) {
524*4a5d661aSToomas Soome 		namelen = isonum_711(ep->name_len);
525*4a5d661aSToomas Soome 		name = ep->name;
526*4a5d661aSToomas Soome 		if (namelen == 1) {
527*4a5d661aSToomas Soome 			if (ep->name[0] == 0)
528*4a5d661aSToomas Soome 				name = ".";
529*4a5d661aSToomas Soome 			else if (ep->name[0] == 1) {
530*4a5d661aSToomas Soome 				namelen = 2;
531*4a5d661aSToomas Soome 				name = "..";
532*4a5d661aSToomas Soome 			}
533*4a5d661aSToomas Soome 		}
534*4a5d661aSToomas Soome 	}
535*4a5d661aSToomas Soome 	reclen = sizeof(struct dirent) - (MAXNAMLEN+1) + namelen + 1;
536*4a5d661aSToomas Soome 	reclen = (reclen + 3) & ~3;
537*4a5d661aSToomas Soome 
538*4a5d661aSToomas Soome 	d->d_fileno = isonum_733(ep->extent);
539*4a5d661aSToomas Soome 	d->d_reclen = reclen;
540*4a5d661aSToomas Soome 	if (isonum_711(ep->flags) & 2)
541*4a5d661aSToomas Soome 		d->d_type = DT_DIR;
542*4a5d661aSToomas Soome 	else
543*4a5d661aSToomas Soome 		d->d_type = DT_REG;
544*4a5d661aSToomas Soome 	d->d_namlen = namelen;
545*4a5d661aSToomas Soome 
546*4a5d661aSToomas Soome 	bcopy(name, d->d_name, d->d_namlen);
547*4a5d661aSToomas Soome 	d->d_name[d->d_namlen] = 0;
548*4a5d661aSToomas Soome 
549*4a5d661aSToomas Soome 	fp->f_off += isonum_711(ep->length);
550*4a5d661aSToomas Soome 	return (0);
551*4a5d661aSToomas Soome }
552*4a5d661aSToomas Soome 
553*4a5d661aSToomas Soome static int
554*4a5d661aSToomas Soome cd9660_write(struct open_file *f __unused, void *start __unused, size_t size __unused, size_t *resid __unused)
555*4a5d661aSToomas Soome {
556*4a5d661aSToomas Soome 	return EROFS;
557*4a5d661aSToomas Soome }
558*4a5d661aSToomas Soome 
559*4a5d661aSToomas Soome static off_t
560*4a5d661aSToomas Soome cd9660_seek(struct open_file *f, off_t offset, int where)
561*4a5d661aSToomas Soome {
562*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
563*4a5d661aSToomas Soome 
564*4a5d661aSToomas Soome 	switch (where) {
565*4a5d661aSToomas Soome 	case SEEK_SET:
566*4a5d661aSToomas Soome 		fp->f_off = offset;
567*4a5d661aSToomas Soome 		break;
568*4a5d661aSToomas Soome 	case SEEK_CUR:
569*4a5d661aSToomas Soome 		fp->f_off += offset;
570*4a5d661aSToomas Soome 		break;
571*4a5d661aSToomas Soome 	case SEEK_END:
572*4a5d661aSToomas Soome 		fp->f_off = fp->f_size - offset;
573*4a5d661aSToomas Soome 		break;
574*4a5d661aSToomas Soome 	default:
575*4a5d661aSToomas Soome 		return -1;
576*4a5d661aSToomas Soome 	}
577*4a5d661aSToomas Soome 	return fp->f_off;
578*4a5d661aSToomas Soome }
579*4a5d661aSToomas Soome 
580*4a5d661aSToomas Soome static int
581*4a5d661aSToomas Soome cd9660_stat(struct open_file *f, struct stat *sb)
582*4a5d661aSToomas Soome {
583*4a5d661aSToomas Soome 	struct file *fp = (struct file *)f->f_fsdata;
584*4a5d661aSToomas Soome 
585*4a5d661aSToomas Soome 	/* only important stuff */
586*4a5d661aSToomas Soome 	sb->st_mode = S_IRUSR | S_IRGRP | S_IROTH;
587*4a5d661aSToomas Soome 	if (fp->f_flags & F_ISDIR)
588*4a5d661aSToomas Soome 		sb->st_mode |= S_IFDIR;
589*4a5d661aSToomas Soome 	else
590*4a5d661aSToomas Soome 		sb->st_mode |= S_IFREG;
591*4a5d661aSToomas Soome 	sb->st_uid = sb->st_gid = 0;
592*4a5d661aSToomas Soome 	sb->st_size = fp->f_size;
593*4a5d661aSToomas Soome 	return 0;
594*4a5d661aSToomas Soome }
595