xref: /minix3/sys/lib/libsa/cd9660.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: cd9660.c,v 1.30 2014/03/20 03:13:18 christos Exp $	*/
258a2b000SEvgeniy Ivanov 
358a2b000SEvgeniy Ivanov /*
458a2b000SEvgeniy Ivanov  * Copyright (C) 1996 Wolfgang Solfrank.
558a2b000SEvgeniy Ivanov  * Copyright (C) 1996 TooLs GmbH.
658a2b000SEvgeniy Ivanov  * All rights reserved.
758a2b000SEvgeniy Ivanov  *
858a2b000SEvgeniy Ivanov  * Redistribution and use in source and binary forms, with or without
958a2b000SEvgeniy Ivanov  * modification, are permitted provided that the following conditions
1058a2b000SEvgeniy Ivanov  * are met:
1158a2b000SEvgeniy Ivanov  * 1. Redistributions of source code must retain the above copyright
1258a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer.
1358a2b000SEvgeniy Ivanov  * 2. Redistributions in binary form must reproduce the above copyright
1458a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer in the
1558a2b000SEvgeniy Ivanov  *    documentation and/or other materials provided with the distribution.
1658a2b000SEvgeniy Ivanov  * 3. All advertising materials mentioning features or use of this software
1758a2b000SEvgeniy Ivanov  *    must display the following acknowledgement:
1858a2b000SEvgeniy Ivanov  *	This product includes software developed by TooLs GmbH.
1958a2b000SEvgeniy Ivanov  * 4. The name of TooLs GmbH may not be used to endorse or promote products
2058a2b000SEvgeniy Ivanov  *    derived from this software without specific prior written permission.
2158a2b000SEvgeniy Ivanov  *
2258a2b000SEvgeniy Ivanov  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2358a2b000SEvgeniy Ivanov  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2458a2b000SEvgeniy Ivanov  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2558a2b000SEvgeniy Ivanov  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2658a2b000SEvgeniy Ivanov  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2758a2b000SEvgeniy Ivanov  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2858a2b000SEvgeniy Ivanov  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2958a2b000SEvgeniy Ivanov  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
3058a2b000SEvgeniy Ivanov  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
3158a2b000SEvgeniy Ivanov  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3258a2b000SEvgeniy Ivanov  */
3358a2b000SEvgeniy Ivanov 
3458a2b000SEvgeniy Ivanov /*
3558a2b000SEvgeniy Ivanov  * Stand-alone ISO9660 file reading package.
3658a2b000SEvgeniy Ivanov  *
3758a2b000SEvgeniy Ivanov  * Note: This doesn't support Rock Ridge extensions, extended attributes,
3858a2b000SEvgeniy Ivanov  * blocksizes other than 2048 bytes, multi-extent files, etc.
3958a2b000SEvgeniy Ivanov  */
4058a2b000SEvgeniy Ivanov #include <sys/param.h>
4158a2b000SEvgeniy Ivanov #ifdef _STANDALONE
4258a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
4358a2b000SEvgeniy Ivanov #else
4458a2b000SEvgeniy Ivanov #include <string.h>
4558a2b000SEvgeniy Ivanov #endif
4658a2b000SEvgeniy Ivanov #include <fs/cd9660/iso.h>
4758a2b000SEvgeniy Ivanov 
4858a2b000SEvgeniy Ivanov #include "stand.h"
4958a2b000SEvgeniy Ivanov #include "cd9660.h"
5058a2b000SEvgeniy Ivanov 
5158a2b000SEvgeniy Ivanov /*
5258a2b000SEvgeniy Ivanov  * XXX Does not currently implement:
5358a2b000SEvgeniy Ivanov  * XXX
5458a2b000SEvgeniy Ivanov  * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?)
5558a2b000SEvgeniy Ivanov  * XXX LIBSA_FS_SINGLECOMPONENT
5658a2b000SEvgeniy Ivanov  */
5758a2b000SEvgeniy Ivanov 
5858a2b000SEvgeniy Ivanov struct file {
5958a2b000SEvgeniy Ivanov 	off_t off;			/* Current offset within file */
6058a2b000SEvgeniy Ivanov 	daddr_t bno;			/* Starting block number  */
6158a2b000SEvgeniy Ivanov 	off_t size;			/* Size of file */
6258a2b000SEvgeniy Ivanov };
6358a2b000SEvgeniy Ivanov 
6458a2b000SEvgeniy Ivanov struct ptable_ent {
6558a2b000SEvgeniy Ivanov 	char namlen	[ISODCL( 1, 1)];	/* 711 */
6658a2b000SEvgeniy Ivanov 	char extlen	[ISODCL( 2, 2)];	/* 711 */
6758a2b000SEvgeniy Ivanov 	char block	[ISODCL( 3, 6)];	/* 732 */
6858a2b000SEvgeniy Ivanov 	char parent	[ISODCL( 7, 8)];	/* 722 */
6958a2b000SEvgeniy Ivanov 	char name	[1];
7058a2b000SEvgeniy Ivanov };
7158a2b000SEvgeniy Ivanov #define	PTFIXSZ		8
7258a2b000SEvgeniy Ivanov #define	PTSIZE(pp)	roundup(PTFIXSZ + isonum_711((pp)->namlen), 2)
7358a2b000SEvgeniy Ivanov 
7458a2b000SEvgeniy Ivanov #define	cdb2devb(bno)	((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)
7558a2b000SEvgeniy Ivanov 
7658a2b000SEvgeniy Ivanov static int	pnmatch(const char *, struct ptable_ent *);
7758a2b000SEvgeniy Ivanov static int	dirmatch(const char *, struct iso_directory_record *);
7858a2b000SEvgeniy Ivanov 
7958a2b000SEvgeniy Ivanov static int
pnmatch(const char * path,struct ptable_ent * pp)8058a2b000SEvgeniy Ivanov pnmatch(const char *path, struct ptable_ent *pp)
8158a2b000SEvgeniy Ivanov {
8258a2b000SEvgeniy Ivanov 	char *cp;
8358a2b000SEvgeniy Ivanov 	int i;
8458a2b000SEvgeniy Ivanov 
8558a2b000SEvgeniy Ivanov 	cp = pp->name;
8658a2b000SEvgeniy Ivanov 	for (i = isonum_711(pp->namlen); --i >= 0; path++, cp++) {
8758a2b000SEvgeniy Ivanov 		if (toupper(*path) == *cp)
8858a2b000SEvgeniy Ivanov 			continue;
8958a2b000SEvgeniy Ivanov 		return 0;
9058a2b000SEvgeniy Ivanov 	}
9158a2b000SEvgeniy Ivanov 	if (*path != '/')
9258a2b000SEvgeniy Ivanov 		return 0;
9358a2b000SEvgeniy Ivanov 	return 1;
9458a2b000SEvgeniy Ivanov }
9558a2b000SEvgeniy Ivanov 
9658a2b000SEvgeniy Ivanov static int
dirmatch(const char * path,struct iso_directory_record * dp)9758a2b000SEvgeniy Ivanov dirmatch(const char *path, struct iso_directory_record *dp)
9858a2b000SEvgeniy Ivanov {
9958a2b000SEvgeniy Ivanov 	char *cp;
10058a2b000SEvgeniy Ivanov 	int i;
10158a2b000SEvgeniy Ivanov 
10258a2b000SEvgeniy Ivanov 	/* This needs to be a regular file */
10358a2b000SEvgeniy Ivanov 	if (dp->flags[0] & 6)
10458a2b000SEvgeniy Ivanov 		return 0;
10558a2b000SEvgeniy Ivanov 
10658a2b000SEvgeniy Ivanov 	cp = dp->name;
10758a2b000SEvgeniy Ivanov 	for (i = isonum_711(dp->name_len); --i >= 0; path++, cp++) {
10858a2b000SEvgeniy Ivanov 		if (!*path)
10958a2b000SEvgeniy Ivanov 			break;
11058a2b000SEvgeniy Ivanov 		if (toupper(*path) == *cp)
11158a2b000SEvgeniy Ivanov 			continue;
11258a2b000SEvgeniy Ivanov 		return 0;
11358a2b000SEvgeniy Ivanov 	}
11458a2b000SEvgeniy Ivanov 	if (*path)
11558a2b000SEvgeniy Ivanov 		return 0;
11658a2b000SEvgeniy Ivanov 	/*
11758a2b000SEvgeniy Ivanov 	 * Allow stripping of trailing dots and the version number.
11858a2b000SEvgeniy Ivanov 	 * Note that this will find the first instead of the last version
11958a2b000SEvgeniy Ivanov 	 * of a file.
12058a2b000SEvgeniy Ivanov 	 */
12158a2b000SEvgeniy Ivanov 	if (i >= 0 && (*cp == ';' || *cp == '.')) {
12258a2b000SEvgeniy Ivanov 		/* This is to prevent matching of numeric extensions */
12358a2b000SEvgeniy Ivanov 		if (*cp == '.' && cp[1] != ';')
12458a2b000SEvgeniy Ivanov 			return 0;
12558a2b000SEvgeniy Ivanov 		while (--i >= 0)
12658a2b000SEvgeniy Ivanov 			if (*++cp != ';' && (*cp < '0' || *cp > '9'))
12758a2b000SEvgeniy Ivanov 				return 0;
12858a2b000SEvgeniy Ivanov 	}
12958a2b000SEvgeniy Ivanov 	return 1;
13058a2b000SEvgeniy Ivanov }
13158a2b000SEvgeniy Ivanov 
13258a2b000SEvgeniy Ivanov __compactcall int
cd9660_open(const char * path,struct open_file * f)13358a2b000SEvgeniy Ivanov cd9660_open(const char *path, struct open_file *f)
13458a2b000SEvgeniy Ivanov {
13558a2b000SEvgeniy Ivanov 	struct file *fp = 0;
13658a2b000SEvgeniy Ivanov 	void *buf;
13758a2b000SEvgeniy Ivanov 	struct iso_primary_descriptor *vd;
13858a2b000SEvgeniy Ivanov 	size_t buf_size, nread, psize, dsize;
13958a2b000SEvgeniy Ivanov 	daddr_t bno;
14058a2b000SEvgeniy Ivanov 	int parent, ent;
14158a2b000SEvgeniy Ivanov 	struct ptable_ent *pp;
14258a2b000SEvgeniy Ivanov 	struct iso_directory_record *dp = 0;
14358a2b000SEvgeniy Ivanov 	int rc;
14458a2b000SEvgeniy Ivanov 
14558a2b000SEvgeniy Ivanov 	/* First find the volume descriptor */
14658a2b000SEvgeniy Ivanov 	buf_size = ISO_DEFAULT_BLOCK_SIZE;
14758a2b000SEvgeniy Ivanov 	buf = alloc(buf_size);
14858a2b000SEvgeniy Ivanov 	vd = buf;
14958a2b000SEvgeniy Ivanov 	for (bno = 16;; bno++) {
15058a2b000SEvgeniy Ivanov #if !defined(LIBSA_NO_TWIDDLE)
15158a2b000SEvgeniy Ivanov 		twiddle();
15258a2b000SEvgeniy Ivanov #endif
15358a2b000SEvgeniy Ivanov 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, cdb2devb(bno),
15458a2b000SEvgeniy Ivanov 					   ISO_DEFAULT_BLOCK_SIZE, buf, &nread);
15558a2b000SEvgeniy Ivanov 		if (rc)
15658a2b000SEvgeniy Ivanov 			goto out;
15758a2b000SEvgeniy Ivanov 		if (nread != ISO_DEFAULT_BLOCK_SIZE) {
15858a2b000SEvgeniy Ivanov 			rc = EIO;
15958a2b000SEvgeniy Ivanov 			goto out;
16058a2b000SEvgeniy Ivanov 		}
16158a2b000SEvgeniy Ivanov 		rc = EINVAL;
16258a2b000SEvgeniy Ivanov 		if (memcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0)
16358a2b000SEvgeniy Ivanov 			goto out;
16458a2b000SEvgeniy Ivanov 		if (isonum_711(vd->type) == ISO_VD_END)
16558a2b000SEvgeniy Ivanov 			goto out;
16658a2b000SEvgeniy Ivanov 		if (isonum_711(vd->type) == ISO_VD_PRIMARY)
16758a2b000SEvgeniy Ivanov 			break;
16858a2b000SEvgeniy Ivanov 	}
16958a2b000SEvgeniy Ivanov 	if (isonum_723(vd->logical_block_size) != ISO_DEFAULT_BLOCK_SIZE)
17058a2b000SEvgeniy Ivanov 		goto out;
17158a2b000SEvgeniy Ivanov 
17258a2b000SEvgeniy Ivanov 	/* Now get the path table and lookup the directory of the file */
17358a2b000SEvgeniy Ivanov 	bno = isonum_732(vd->type_m_path_table);
17458a2b000SEvgeniy Ivanov 	psize = isonum_733(vd->path_table_size);
17558a2b000SEvgeniy Ivanov 
17658a2b000SEvgeniy Ivanov 	if (psize > ISO_DEFAULT_BLOCK_SIZE) {
17758a2b000SEvgeniy Ivanov 		dealloc(buf, ISO_DEFAULT_BLOCK_SIZE);
17858a2b000SEvgeniy Ivanov 		buf = alloc(buf_size = roundup(psize, ISO_DEFAULT_BLOCK_SIZE));
17958a2b000SEvgeniy Ivanov 	}
18058a2b000SEvgeniy Ivanov 
18158a2b000SEvgeniy Ivanov #if !defined(LIBSA_NO_TWIDDLE)
18258a2b000SEvgeniy Ivanov 	twiddle();
18358a2b000SEvgeniy Ivanov #endif
18458a2b000SEvgeniy Ivanov 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, cdb2devb(bno),
18558a2b000SEvgeniy Ivanov 	                           buf_size, buf, &nread);
18658a2b000SEvgeniy Ivanov 	if (rc)
18758a2b000SEvgeniy Ivanov 		goto out;
18858a2b000SEvgeniy Ivanov 	if (nread != buf_size) {
18958a2b000SEvgeniy Ivanov 		rc = EIO;
19058a2b000SEvgeniy Ivanov 		goto out;
19158a2b000SEvgeniy Ivanov 	}
19258a2b000SEvgeniy Ivanov 
19358a2b000SEvgeniy Ivanov 	parent = 1;
19458a2b000SEvgeniy Ivanov 	pp = (struct ptable_ent *)buf;
19558a2b000SEvgeniy Ivanov 	ent = 1;
19658a2b000SEvgeniy Ivanov 	bno = isonum_732(pp->block) + isonum_711(pp->extlen);
19758a2b000SEvgeniy Ivanov 
19858a2b000SEvgeniy Ivanov 	rc = ENOENT;
19958a2b000SEvgeniy Ivanov 
20058a2b000SEvgeniy Ivanov 	while (*path) {
20158a2b000SEvgeniy Ivanov 		/*
20258a2b000SEvgeniy Ivanov 		 * Remove extra separators
20358a2b000SEvgeniy Ivanov 		 */
20458a2b000SEvgeniy Ivanov 		while (*path == '/')
20558a2b000SEvgeniy Ivanov 			path++;
20658a2b000SEvgeniy Ivanov 
20758a2b000SEvgeniy Ivanov 		if ((char *)pp >= (char *)buf + psize)
20858a2b000SEvgeniy Ivanov 			break;
20958a2b000SEvgeniy Ivanov 		if (isonum_722(pp->parent) != parent)
21058a2b000SEvgeniy Ivanov 			break;
21158a2b000SEvgeniy Ivanov 		if (!pnmatch(path, pp)) {
21258a2b000SEvgeniy Ivanov 			pp = (struct ptable_ent *)((char *)pp + PTSIZE(pp));
21358a2b000SEvgeniy Ivanov 			ent++;
21458a2b000SEvgeniy Ivanov 			continue;
21558a2b000SEvgeniy Ivanov 		}
21658a2b000SEvgeniy Ivanov 		path += isonum_711(pp->namlen) + 1;
21758a2b000SEvgeniy Ivanov 		parent = ent;
21858a2b000SEvgeniy Ivanov 		bno = isonum_732(pp->block) + isonum_711(pp->extlen);
21958a2b000SEvgeniy Ivanov 		while ((char *)pp < (char *)buf + psize) {
22058a2b000SEvgeniy Ivanov 			if (isonum_722(pp->parent) == parent)
22158a2b000SEvgeniy Ivanov 				break;
22258a2b000SEvgeniy Ivanov 			pp = (struct ptable_ent *)((char *)pp + PTSIZE(pp));
22358a2b000SEvgeniy Ivanov 			ent++;
22458a2b000SEvgeniy Ivanov 		}
22558a2b000SEvgeniy Ivanov 	}
22658a2b000SEvgeniy Ivanov 
22758a2b000SEvgeniy Ivanov 	/*
22858a2b000SEvgeniy Ivanov 	 * Now bno has the start of the directory that supposedly
22958a2b000SEvgeniy Ivanov 	 * contains the file
23058a2b000SEvgeniy Ivanov 	 */
23158a2b000SEvgeniy Ivanov 	bno--;
23258a2b000SEvgeniy Ivanov 	dsize = 1;		/* Something stupid, but > 0 XXX */
23358a2b000SEvgeniy Ivanov 	for (psize = 0; psize < dsize;) {
23458a2b000SEvgeniy Ivanov 		if (!(psize % ISO_DEFAULT_BLOCK_SIZE)) {
23558a2b000SEvgeniy Ivanov 			bno++;
23658a2b000SEvgeniy Ivanov #if !defined(LIBSA_NO_TWIDDLE)
23758a2b000SEvgeniy Ivanov 			twiddle();
23858a2b000SEvgeniy Ivanov #endif
23958a2b000SEvgeniy Ivanov 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
24058a2b000SEvgeniy Ivanov 			                           cdb2devb(bno),
24158a2b000SEvgeniy Ivanov 			                           ISO_DEFAULT_BLOCK_SIZE,
24258a2b000SEvgeniy Ivanov 			                           buf, &nread);
24358a2b000SEvgeniy Ivanov 			if (rc)
24458a2b000SEvgeniy Ivanov 				goto out;
24558a2b000SEvgeniy Ivanov 			if (nread != ISO_DEFAULT_BLOCK_SIZE) {
24658a2b000SEvgeniy Ivanov 				rc = EIO;
24758a2b000SEvgeniy Ivanov 				goto out;
24858a2b000SEvgeniy Ivanov 			}
24958a2b000SEvgeniy Ivanov 			dp = (struct iso_directory_record *)buf;
25058a2b000SEvgeniy Ivanov 		}
25158a2b000SEvgeniy Ivanov 		if (!isonum_711(dp->length)) {
25258a2b000SEvgeniy Ivanov 			if ((void *)dp == buf)
25358a2b000SEvgeniy Ivanov 				psize += ISO_DEFAULT_BLOCK_SIZE;
25458a2b000SEvgeniy Ivanov 			else
25558a2b000SEvgeniy Ivanov 				psize = roundup(psize, ISO_DEFAULT_BLOCK_SIZE);
25658a2b000SEvgeniy Ivanov 			continue;
25758a2b000SEvgeniy Ivanov 		}
25858a2b000SEvgeniy Ivanov 		if (dsize == 1)
25958a2b000SEvgeniy Ivanov 			dsize = isonum_733(dp->size);
26058a2b000SEvgeniy Ivanov 		if (dirmatch(path, dp))
26158a2b000SEvgeniy Ivanov 			break;
26258a2b000SEvgeniy Ivanov 		psize += isonum_711(dp->length);
26358a2b000SEvgeniy Ivanov 		dp = (struct iso_directory_record *)
26458a2b000SEvgeniy Ivanov 			((char *)dp + isonum_711(dp->length));
26558a2b000SEvgeniy Ivanov 	}
26658a2b000SEvgeniy Ivanov 
26758a2b000SEvgeniy Ivanov 	if (psize >= dsize) {
26858a2b000SEvgeniy Ivanov 		rc = ENOENT;
26958a2b000SEvgeniy Ivanov 		goto out;
27058a2b000SEvgeniy Ivanov 	}
27158a2b000SEvgeniy Ivanov 
27258a2b000SEvgeniy Ivanov 	/* allocate file system specific data structure */
27358a2b000SEvgeniy Ivanov 	fp = alloc(sizeof(struct file));
27458a2b000SEvgeniy Ivanov 	memset(fp, 0, sizeof(struct file));
27558a2b000SEvgeniy Ivanov 	f->f_fsdata = (void *)fp;
27658a2b000SEvgeniy Ivanov 
27758a2b000SEvgeniy Ivanov 	fp->off = 0;
27858a2b000SEvgeniy Ivanov 	fp->bno = isonum_733(dp->extent);
27958a2b000SEvgeniy Ivanov 	fp->size = isonum_733(dp->size);
28058a2b000SEvgeniy Ivanov 	dealloc(buf, buf_size);
28158a2b000SEvgeniy Ivanov 	fsmod = "cd9660";
28258a2b000SEvgeniy Ivanov 
28358a2b000SEvgeniy Ivanov 	return 0;
28458a2b000SEvgeniy Ivanov 
28558a2b000SEvgeniy Ivanov out:
28658a2b000SEvgeniy Ivanov 	if (fp)
28758a2b000SEvgeniy Ivanov 		dealloc(fp, sizeof(struct file));
28858a2b000SEvgeniy Ivanov 	dealloc(buf, buf_size);
28958a2b000SEvgeniy Ivanov 
29058a2b000SEvgeniy Ivanov 	return rc;
29158a2b000SEvgeniy Ivanov }
29258a2b000SEvgeniy Ivanov 
29358a2b000SEvgeniy Ivanov #if !defined(LIBSA_NO_FS_CLOSE)
29458a2b000SEvgeniy Ivanov __compactcall int
cd9660_close(struct open_file * f)29558a2b000SEvgeniy Ivanov cd9660_close(struct open_file *f)
29658a2b000SEvgeniy Ivanov {
29758a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
29858a2b000SEvgeniy Ivanov 
29958a2b000SEvgeniy Ivanov 	f->f_fsdata = 0;
30058a2b000SEvgeniy Ivanov 	dealloc(fp, sizeof *fp);
30158a2b000SEvgeniy Ivanov 
30258a2b000SEvgeniy Ivanov 	return 0;
30358a2b000SEvgeniy Ivanov }
30458a2b000SEvgeniy Ivanov #endif /* !defined(LIBSA_NO_FS_CLOSE) */
30558a2b000SEvgeniy Ivanov 
30658a2b000SEvgeniy Ivanov __compactcall int
cd9660_read(struct open_file * f,void * start,size_t size,size_t * resid)30758a2b000SEvgeniy Ivanov cd9660_read(struct open_file *f, void *start, size_t size, size_t *resid)
30858a2b000SEvgeniy Ivanov {
30958a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
31058a2b000SEvgeniy Ivanov 	int rc = 0;
31158a2b000SEvgeniy Ivanov 	daddr_t bno;
31258a2b000SEvgeniy Ivanov 	char buf[ISO_DEFAULT_BLOCK_SIZE];
31358a2b000SEvgeniy Ivanov 	char *dp;
31458a2b000SEvgeniy Ivanov 	size_t nread, off;
31558a2b000SEvgeniy Ivanov 
31658a2b000SEvgeniy Ivanov 	while (size) {
31758a2b000SEvgeniy Ivanov 		if (fp->off < 0 || fp->off >= fp->size)
31858a2b000SEvgeniy Ivanov 			break;
31958a2b000SEvgeniy Ivanov 		bno = fp->off / ISO_DEFAULT_BLOCK_SIZE + fp->bno;
32058a2b000SEvgeniy Ivanov 		if (fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1)
321f14fb602SLionel Sambuc 		    || (fp->off + ISO_DEFAULT_BLOCK_SIZE) > fp->size
32258a2b000SEvgeniy Ivanov 		    || size < ISO_DEFAULT_BLOCK_SIZE)
32358a2b000SEvgeniy Ivanov 			dp = buf;
32458a2b000SEvgeniy Ivanov 		else
32558a2b000SEvgeniy Ivanov 			dp = start;
32658a2b000SEvgeniy Ivanov #if !defined(LIBSA_NO_TWIDDLE)
32758a2b000SEvgeniy Ivanov 		twiddle();
32858a2b000SEvgeniy Ivanov #endif
32958a2b000SEvgeniy Ivanov 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, cdb2devb(bno),
33058a2b000SEvgeniy Ivanov 		                            ISO_DEFAULT_BLOCK_SIZE, dp, &nread);
33158a2b000SEvgeniy Ivanov 		if (rc)
33258a2b000SEvgeniy Ivanov 			return rc;
33358a2b000SEvgeniy Ivanov 		if (nread != ISO_DEFAULT_BLOCK_SIZE)
33458a2b000SEvgeniy Ivanov 			return EIO;
33558a2b000SEvgeniy Ivanov 		if (dp == buf) {
33658a2b000SEvgeniy Ivanov 			off = fp->off & (ISO_DEFAULT_BLOCK_SIZE - 1);
33758a2b000SEvgeniy Ivanov 			if (nread > off + size)
33858a2b000SEvgeniy Ivanov 				nread = off + size;
33958a2b000SEvgeniy Ivanov 			nread -= off;
340f14fb602SLionel Sambuc 			if (nread > fp->size - fp->off)
341f14fb602SLionel Sambuc 				nread = fp->size - fp->off;
34258a2b000SEvgeniy Ivanov 			memcpy(start, buf + off, nread);
34358a2b000SEvgeniy Ivanov 			start = (char *)start + nread;
34458a2b000SEvgeniy Ivanov 			fp->off += nread;
34558a2b000SEvgeniy Ivanov 			size -= nread;
34658a2b000SEvgeniy Ivanov 		} else {
34758a2b000SEvgeniy Ivanov 			start = (char *)start + ISO_DEFAULT_BLOCK_SIZE;
34858a2b000SEvgeniy Ivanov 			fp->off += ISO_DEFAULT_BLOCK_SIZE;
34958a2b000SEvgeniy Ivanov 			size -= ISO_DEFAULT_BLOCK_SIZE;
35058a2b000SEvgeniy Ivanov 		}
35158a2b000SEvgeniy Ivanov 	}
35258a2b000SEvgeniy Ivanov 	if(fp->off > fp->size)
35358a2b000SEvgeniy Ivanov 		size += fp->off - fp->size;
35458a2b000SEvgeniy Ivanov 	if (resid)
35558a2b000SEvgeniy Ivanov 		*resid = size;
35658a2b000SEvgeniy Ivanov 	return rc;
35758a2b000SEvgeniy Ivanov }
35858a2b000SEvgeniy Ivanov 
35958a2b000SEvgeniy Ivanov #if !defined(LIBSA_NO_FS_WRITE)
36058a2b000SEvgeniy Ivanov __compactcall int
cd9660_write(struct open_file * f,void * start,size_t size,size_t * resid)36158a2b000SEvgeniy Ivanov cd9660_write(struct open_file *f, void *start, size_t size, size_t *resid)
36258a2b000SEvgeniy Ivanov {
36358a2b000SEvgeniy Ivanov 
36458a2b000SEvgeniy Ivanov 	return EROFS;
36558a2b000SEvgeniy Ivanov }
36658a2b000SEvgeniy Ivanov #endif /* !defined(LIBSA_NO_FS_WRITE) */
36758a2b000SEvgeniy Ivanov 
36858a2b000SEvgeniy Ivanov #if !defined(LIBSA_NO_FS_SEEK)
36958a2b000SEvgeniy Ivanov __compactcall off_t
cd9660_seek(struct open_file * f,off_t offset,int where)37058a2b000SEvgeniy Ivanov cd9660_seek(struct open_file *f, off_t offset, int where)
37158a2b000SEvgeniy Ivanov {
37258a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
37358a2b000SEvgeniy Ivanov 
37458a2b000SEvgeniy Ivanov 	switch (where) {
37558a2b000SEvgeniy Ivanov 	case SEEK_SET:
37658a2b000SEvgeniy Ivanov 		fp->off = offset;
37758a2b000SEvgeniy Ivanov 		break;
37858a2b000SEvgeniy Ivanov 	case SEEK_CUR:
37958a2b000SEvgeniy Ivanov 		fp->off += offset;
38058a2b000SEvgeniy Ivanov 		break;
38158a2b000SEvgeniy Ivanov 	case SEEK_END:
38258a2b000SEvgeniy Ivanov 		fp->off = fp->size - offset;
38358a2b000SEvgeniy Ivanov 		break;
38458a2b000SEvgeniy Ivanov 	default:
38558a2b000SEvgeniy Ivanov 		return -1;
38658a2b000SEvgeniy Ivanov 	}
38758a2b000SEvgeniy Ivanov 	return fp->off;
38858a2b000SEvgeniy Ivanov }
38958a2b000SEvgeniy Ivanov #endif /* !defined(LIBSA_NO_FS_SEEK) */
39058a2b000SEvgeniy Ivanov 
39158a2b000SEvgeniy Ivanov __compactcall int
cd9660_stat(struct open_file * f,struct stat * sb)39258a2b000SEvgeniy Ivanov cd9660_stat(struct open_file *f, struct stat *sb)
39358a2b000SEvgeniy Ivanov {
39458a2b000SEvgeniy Ivanov 	struct file *fp = (struct file *)f->f_fsdata;
39558a2b000SEvgeniy Ivanov 
39658a2b000SEvgeniy Ivanov 	/* only importatn stuff */
39758a2b000SEvgeniy Ivanov 	sb->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
39858a2b000SEvgeniy Ivanov 	sb->st_uid = sb->st_gid = 0;
39958a2b000SEvgeniy Ivanov 	sb->st_size = fp->size;
40058a2b000SEvgeniy Ivanov 	return 0;
40158a2b000SEvgeniy Ivanov }
40258a2b000SEvgeniy Ivanov 
40358a2b000SEvgeniy Ivanov #if defined(LIBSA_ENABLE_LS_OP)
404*0a6a1f1dSLionel Sambuc #include "ls.h"
40558a2b000SEvgeniy Ivanov __compactcall void
cd9660_ls(struct open_file * f,const char * pattern)406*0a6a1f1dSLionel Sambuc cd9660_ls(struct open_file *f, const char *pattern)
40758a2b000SEvgeniy Ivanov {
408*0a6a1f1dSLionel Sambuc 	lsunsup("cd9660");
40958a2b000SEvgeniy Ivanov }
410*0a6a1f1dSLionel Sambuc 
411*0a6a1f1dSLionel Sambuc #if defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP)
412*0a6a1f1dSLionel Sambuc __compactcall void
cd9660_load_mods(struct open_file * f,const char * pattern,void (* funcp)(char *),char * path)413*0a6a1f1dSLionel Sambuc cd9660_load_mods(struct open_file *f, const char *pattern,
414*0a6a1f1dSLionel Sambuc 	void (*funcp)(char *), char *path)
415*0a6a1f1dSLionel Sambuc {
416*0a6a1f1dSLionel Sambuc 	load_modsunsup("cd9660");
417*0a6a1f1dSLionel Sambuc }
418*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP) */
41958a2b000SEvgeniy Ivanov #endif
420