17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5986fd29setje * Common Development and Distribution License (the "License").
6986fd29setje * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
22986fd29setje * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bdstevel@tonic-gate * Use is subject to license terms.
247c478bdstevel@tonic-gate */
257c478bdstevel@tonic-gate
267c478bdstevel@tonic-gate#include <sys/param.h>
277c478bdstevel@tonic-gate#include <sys/vnode.h>
287c478bdstevel@tonic-gate#include <sys/fs/ufs_fsdir.h>
297c478bdstevel@tonic-gate#include <sys/fs/ufs_fs.h>
307c478bdstevel@tonic-gate#include <sys/fs/ufs_inode.h>
317c478bdstevel@tonic-gate#include <sys/sysmacros.h>
327c478bdstevel@tonic-gate#include <sys/promif.h>
337c478bdstevel@tonic-gate#include <sys/filep.h>
347c478bdstevel@tonic-gate#include <sys/salib.h>
357c478bdstevel@tonic-gate#include <sys/sacache.h>
367c478bdstevel@tonic-gate
377c478bdstevel@tonic-gate#include <sys/fs/hsfs_spec.h>
387c478bdstevel@tonic-gate#include <sys/fs/hsfs_isospec.h>
397c478bdstevel@tonic-gate#include <sys/fs/hsfs_node.h>
407c478bdstevel@tonic-gate#include <sys/fs/hsfs_susp.h>
417c478bdstevel@tonic-gate#include <sys/fs/hsfs_rrip.h>
427c478bdstevel@tonic-gate
437c478bdstevel@tonic-gate#include "hsfs_sig.h"
447c478bdstevel@tonic-gate
457c478bdstevel@tonic-gate#include <sys/stat.h>
467c478bdstevel@tonic-gate#include <sys/bootvfs.h>
477c478bdstevel@tonic-gate#include <sys/bootconf.h>
487c478bdstevel@tonic-gate#include <sys/bootdebug.h>
497c478bdstevel@tonic-gate
507c478bdstevel@tonic-gate#define	hdbtodb(n)	((ISO_SECTOR_SIZE / DEV_BSIZE) * (n))
517c478bdstevel@tonic-gate
527c478bdstevel@tonic-gate#define	THE_EPOCH	1970
537c478bdstevel@tonic-gate#define	END_OF_TIME	2099
547c478bdstevel@tonic-gate
557c478bdstevel@tonic-gate/* May not need this... */
567c478bdstevel@tonic-gatestatic uint_t	sua_offset = 0;
577c478bdstevel@tonic-gate
587c478bdstevel@tonic-gate/* The root inode on an HSFS filesystem can be anywhere! */
597c478bdstevel@tonic-gatestatic uint_t	root_ino = 0;		/* This is both a flag and a value */
607c478bdstevel@tonic-gate
617c478bdstevel@tonic-gatestatic fileid_t *head;
627c478bdstevel@tonic-gate
637c478bdstevel@tonic-gate/* Only got one of these...ergo, only 1 fs open at once */
647c478bdstevel@tonic-gatestatic devid_t *devp;
657c478bdstevel@tonic-gate
667c478bdstevel@tonic-gatestruct dirinfo {
677c478bdstevel@tonic-gate	int 	loc;
687c478bdstevel@tonic-gate	fileid_t *fi;
697c478bdstevel@tonic-gate};
707c478bdstevel@tonic-gate
717c478bdstevel@tonic-gatestruct hs_direct {
727c478bdstevel@tonic-gate    struct	direct	hs_ufs_dir;
737c478bdstevel@tonic-gate    struct	hs_direntry hs_dir;
747c478bdstevel@tonic-gate};
757c478bdstevel@tonic-gate
767c478bdstevel@tonic-gate/*
777c478bdstevel@tonic-gate *  Function prototypes
787c478bdstevel@tonic-gate */
797c478bdstevel@tonic-gate
807c478bdstevel@tonic-gatestatic int	boot_hsfs_mountroot(char *str);
817c478bdstevel@tonic-gatestatic int	boot_hsfs_unmountroot(void);
827c478bdstevel@tonic-gatestatic int	boot_hsfs_open(char *filename, int flags);
837c478bdstevel@tonic-gatestatic int	boot_hsfs_close(int fd);
847c478bdstevel@tonic-gatestatic ssize_t	boot_hsfs_read(int fd, caddr_t buf, size_t size);
857c478bdstevel@tonic-gatestatic off_t	boot_hsfs_lseek(int, off_t, int);
867c478bdstevel@tonic-gatestatic int	boot_hsfs_fstat(int fd, struct bootstat *stp);
877c478bdstevel@tonic-gatestatic void	boot_hsfs_closeall(int flag);
887c478bdstevel@tonic-gatestatic int	boot_hsfs_getdents(int fd, struct dirent *dep, unsigned size);
897c478bdstevel@tonic-gate
907c478bdstevel@tonic-gatestruct boot_fs_ops boot_hsfs_ops = {
917c478bdstevel@tonic-gate	"hsfs",
927c478bdstevel@tonic-gate	boot_hsfs_mountroot,
937c478bdstevel@tonic-gate	boot_hsfs_unmountroot,
947c478bdstevel@tonic-gate	boot_hsfs_open,
957c478bdstevel@tonic-gate	boot_hsfs_close,
967c478bdstevel@tonic-gate	boot_hsfs_read,
977c478bdstevel@tonic-gate	boot_hsfs_lseek,
987c478bdstevel@tonic-gate	boot_hsfs_fstat,
997c478bdstevel@tonic-gate	boot_hsfs_closeall,
1007c478bdstevel@tonic-gate	boot_hsfs_getdents
1017c478bdstevel@tonic-gate};
1027c478bdstevel@tonic-gate
1037c478bdstevel@tonic-gatestatic 	ino_t	find(fileid_t *, char *);
1047c478bdstevel@tonic-gatestatic	ino_t	dlook(fileid_t *, char *);
1057c478bdstevel@tonic-gatestatic	int	opendir(fileid_t *, ino_t);
1067c478bdstevel@tonic-gatestatic	struct	hs_direct *readdir(struct dirinfo *);
1077c478bdstevel@tonic-gatestatic	uint_t	parse_dir(fileid_t *, int, struct hs_direct *);
1087c478bdstevel@tonic-gatestatic	uint_t	parse_susp(char *, uint_t *, struct hs_direct *);
1097c478bdstevel@tonic-gatestatic	void	hs_seti(fileid_t *,  struct hs_direct *, ino_t);
1107c478bdstevel@tonic-gatestatic void	hs_dodates(enum hs_vol_type, struct hs_direntry *, char *);
1117c478bdstevel@tonic-gatestatic time_t	hs_date_to_gmtime(int, int, int, int);
1127c478bdstevel@tonic-gate
1137c478bdstevel@tonic-gate/*
1147c478bdstevel@tonic-gate *	There is only 1 open (mounted) device at any given time.
1157c478bdstevel@tonic-gate *	So we can keep a single, global devp file descriptor to
1167c478bdstevel@tonic-gate *	use to index into the di[] array.  This is not true for the
1177c478bdstevel@tonic-gate *	fi[] array.  We can have more than one file open at once,
1187c478bdstevel@tonic-gate *	so there is no global fd for the fi[].
1197c478bdstevel@tonic-gate *	The user program must save the fd passed back from open()
1207c478bdstevel@tonic-gate *	and use it to do subsequent read()'s.
1217c478bdstevel@tonic-gate */
1227c478bdstevel@tonic-gate
1237c478bdstevel@tonic-gatestatic int
1247c478bdstevel@tonic-gateopendir(fileid_t *filep, ino_t inode)
1257c478bdstevel@tonic-gate{
1267c478bdstevel@tonic-gate	struct hs_direct hsdep;
1277c478bdstevel@tonic-gate	int retval;
1287c478bdstevel@tonic-gate
1297c478bdstevel@tonic-gate	/* Set up the saio request */
1307c478bdstevel@tonic-gate	filep->fi_offset = 0;
1317c478bdstevel@tonic-gate	filep->fi_blocknum = hdbtodb(inode);
1327c478bdstevel@tonic-gate	filep->fi_count = ISO_SECTOR_SIZE;
1337c478bdstevel@tonic-gate
1347c478bdstevel@tonic-gate	/* Maybe the block is in the disk block cache */
1357c478bdstevel@tonic-gate	if ((filep->fi_memp = get_bcache(filep)) == NULL) {
1367c478bdstevel@tonic-gate		/* Not in the block cache so read it from disk */
1377c478bdstevel@tonic-gate		if (retval = set_bcache(filep)) {
1387c478bdstevel@tonic-gate			return (retval);
1397c478bdstevel@tonic-gate		}
1407c478bdstevel@tonic-gate	}
1417c478bdstevel@tonic-gate
1427c478bdstevel@tonic-gate	filep->fi_offset = 0;
1437c478bdstevel@tonic-gate	filep->fi_blocknum = hdbtodb(inode);
1447c478bdstevel@tonic-gate
1457c478bdstevel@tonic-gate	if (inode != root_ino)
146986fd29setje		return (0);
1477c478bdstevel@tonic-gate
1487c478bdstevel@tonic-gate	if ((int)(parse_dir(filep, 0, &hsdep)) > 0) {
1497c478bdstevel@tonic-gate		hs_seti(filep, &hsdep, inode);
1507c478bdstevel@tonic-gate		return (0);
1517c478bdstevel@tonic-gate	}
1527c478bdstevel@tonic-gate	return (1);
1537c478bdstevel@tonic-gate}
1547c478bdstevel@tonic-gate
1557c478bdstevel@tonic-gatestatic ino_t
1567c478bdstevel@tonic-gatefind(fileid_t *filep, char *path)
1577c478bdstevel@tonic-gate{
1587c478bdstevel@tonic-gate	register char *q;
1597c478bdstevel@tonic-gate	char c;
1607c478bdstevel@tonic-gate	ino_t inode;
1617c478bdstevel@tonic-gate
1627c478bdstevel@tonic-gate	if (path == NULL || *path == '\0') {
1637c478bdstevel@tonic-gate		printf("null path\n");
1647c478bdstevel@tonic-gate		return (0);
1657c478bdstevel@tonic-gate	}
1667c478bdstevel@tonic-gate
1677c478bdstevel@tonic-gate	if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE))
168986fd29setje		printf("find(): path=<%s>\n", path);
1697c478bdstevel@tonic-gate
1707c478bdstevel@tonic-gate	/* Read the ROOT directory */
1717c478bdstevel@tonic-gate	if (opendir(filep, inode = root_ino)) {
1727c478bdstevel@tonic-gate		printf("find(): root_ino opendir() failed!\n");
1737c478bdstevel@tonic-gate		return ((ino_t)-1);
1747c478bdstevel@tonic-gate	}
1757c478bdstevel@tonic-gate
1767c478bdstevel@tonic-gate	while (*path) {
1777c478bdstevel@tonic-gate		while (*path == '/')
1787c478bdstevel@tonic-gate			path++;
1797c478bdstevel@tonic-gate		if (*(q = path) == '\0')
1807c478bdstevel@tonic-gate			break;
1817c478bdstevel@tonic-gate		while (*q != '/' && *q != '\0')
1827c478bdstevel@tonic-gate			q++;
1837c478bdstevel@tonic-gate		c = *q;
1847c478bdstevel@tonic-gate		*q = '\0';
1857c478bdstevel@tonic-gate
1867c478bdstevel@tonic-gate		if ((inode = dlook(filep, path)) != 0) {
1877c478bdstevel@tonic-gate			if (c == '\0')
1887c478bdstevel@tonic-gate				break;
1897c478bdstevel@tonic-gate			if (opendir(filep, inode)) {
1907c478bdstevel@tonic-gate				printf("find(): opendir(%d) failed!\n", inode);
1917c478bdstevel@tonic-gate				*q = c;
1927c478bdstevel@tonic-gate				return ((ino_t)-1);
1937c478bdstevel@tonic-gate			}
1947c478bdstevel@tonic-gate			*q = c;
1957c478bdstevel@tonic-gate			path = q;
1967c478bdstevel@tonic-gate			continue;
1977c478bdstevel@tonic-gate		} else {
1987c478bdstevel@tonic-gate			*q = c;
1997c478bdstevel@tonic-gate			return (0);
2007c478bdstevel@tonic-gate		}
2017c478bdstevel@tonic-gate	}
2027c478bdstevel@tonic-gate	return (inode);
2037c478bdstevel@tonic-gate}
2047c478bdstevel@tonic-gate
2057c478bdstevel@tonic-gatestatic fileid_t *
2067c478bdstevel@tonic-gatefind_fp(int fd)
2077c478bdstevel@tonic-gate{
2087c478bdstevel@tonic-gate	fileid_t *filep = head;
2097c478bdstevel@tonic-gate
2107c478bdstevel@tonic-gate	if (fd >= 0) {
2117c478bdstevel@tonic-gate		while ((filep = filep->fi_forw) != head)
2127c478bdstevel@tonic-gate			if (fd == filep->fi_filedes)
2137c478bdstevel@tonic-gate				return (filep->fi_taken ? filep : 0);
2147c478bdstevel@tonic-gate	}
2157c478bdstevel@tonic-gate
2167c478bdstevel@tonic-gate	return (0);
2177c478bdstevel@tonic-gate}
2187c478bdstevel@tonic-gate
2197c478bdstevel@tonic-gatestatic ino_t
2207c478bdstevel@tonic-gatedlook(fileid_t *filep, char *path)
2217c478bdstevel@tonic-gate{
2227c478bdstevel@tonic-gate	int dv = filep->fi_devp->di_dcookie;
2237c478bdstevel@tonic-gate	register struct hs_direct *hsdep;
2247c478bdstevel@tonic-gate	register struct direct *udp;
2257c478bdstevel@tonic-gate	register struct inode *ip;
2267c478bdstevel@tonic-gate	struct dirinfo dirp;
2277c478bdstevel@tonic-gate	register int len;
2287c478bdstevel@tonic-gate	ino_t in;
2297c478bdstevel@tonic-gate
2307c478bdstevel@tonic-gate	ip = filep->fi_inode;
2317c478bdstevel@tonic-gate	if (path == NULL || *path == '\0')
2327c478bdstevel@tonic-gate		return (0);
2337c478bdstevel@tonic-gate	if ((ip->i_smode & IFMT) != IFDIR) {
2347c478bdstevel@tonic-gate		return (0);
2357c478bdstevel@tonic-gate	}
2367c478bdstevel@tonic-gate	if (ip->i_size == 0) {
2377c478bdstevel@tonic-gate		return (0);
2387c478bdstevel@tonic-gate	}
2397c478bdstevel@tonic-gate	len = strlen(path);
2407c478bdstevel@tonic-gate	/* first look through the directory entry cache */
2417c478bdstevel@tonic-gate	if (in = get_dcache(dv, path, ip->i_number)) {
2427c478bdstevel@tonic-gate		if ((filep->fi_inode = get_icache(dv, in)) != NULL) {
2437c478bdstevel@tonic-gate			filep->fi_offset = 0;
2447c478bdstevel@tonic-gate			filep->fi_blocknum = hdbtodb(in);
2457c478bdstevel@tonic-gate			return (in);
2467c478bdstevel@tonic-gate		}
2477c478bdstevel@tonic-gate	}
2487c478bdstevel@tonic-gate	dirp.loc = 0;
2497c478bdstevel@tonic-gate	dirp.fi = filep;
2507c478bdstevel@tonic-gate	for (hsdep = readdir(&dirp); hsdep != NULL; hsdep = readdir(&dirp)) {
2517c478bdstevel@tonic-gate		udp = &hsdep->hs_ufs_dir;
2527c478bdstevel@tonic-gate		if (udp->d_namlen == 1 &&
2537c478bdstevel@tonic-gate		    udp->d_name[0] == '.' &&
2547c478bdstevel@tonic-gate		    udp->d_name[1] == '\0')
2557c478bdstevel@tonic-gate			continue;
2567c478bdstevel@tonic-gate		if (udp->d_namlen == 2 &&
2577c478bdstevel@tonic-gate		    udp->d_name[0] == '.' &&
2587c478bdstevel@tonic-gate		    udp->d_name[1] == '.' &&
2597c478bdstevel@tonic-gate		    udp->d_name[2] == '\0')
2607c478bdstevel@tonic-gate			continue;
2617c478bdstevel@tonic-gate		if (udp->d_namlen == len && (strcmp(path, udp->d_name) == 0)) {
2627c478bdstevel@tonic-gate			set_dcache(dv, path, ip->i_number, udp->d_ino);
2637c478bdstevel@tonic-gate			hs_seti(filep, hsdep, udp->d_ino);
2647c478bdstevel@tonic-gate			filep->fi_offset = 0;
2657c478bdstevel@tonic-gate			filep->fi_blocknum = hdbtodb(udp->d_ino);
2667c478bdstevel@tonic-gate			/* put this entry into the cache */
2677c478bdstevel@tonic-gate			return (udp->d_ino);
2687c478bdstevel@tonic-gate		}
2697c478bdstevel@tonic-gate		/* Allow "*" to print all names at that level, w/out match */
2707c478bdstevel@tonic-gate		if (strcmp(path, "*") == 0)
2717c478bdstevel@tonic-gate			printf("%s\n", udp->d_name);
2727c478bdstevel@tonic-gate	}
2737c478bdstevel@tonic-gate	return (0);
2747c478bdstevel@tonic-gate}
2757c478bdstevel@tonic-gate
2767c478bdstevel@tonic-gate/*
2777c478bdstevel@tonic-gate * get next entry in a directory.
2787c478bdstevel@tonic-gate */
2797c478bdstevel@tonic-gatestatic struct hs_direct *
2807c478bdstevel@tonic-gatereaddir(struct dirinfo *dirp)
2817c478bdstevel@tonic-gate{
2827c478bdstevel@tonic-gate	static struct hs_direct hsdep;
2837c478bdstevel@tonic-gate	register struct direct *udp = &hsdep.hs_ufs_dir;
2847c478bdstevel@tonic-gate	register struct inode *ip;
2857c478bdstevel@tonic-gate	register fileid_t *filep;
2867c478bdstevel@tonic-gate	register daddr_t lbn;
2877c478bdstevel@tonic-gate	register int off;
2887c478bdstevel@tonic-gate
2897c478bdstevel@tonic-gate	filep = dirp->fi;
2907c478bdstevel@tonic-gate	ip = filep->fi_inode;
2917c478bdstevel@tonic-gate	for (;;) {
2927c478bdstevel@tonic-gate		if (dirp->loc >= ip->i_size) {
2937c478bdstevel@tonic-gate			return (NULL);
2947c478bdstevel@tonic-gate		}
2957c478bdstevel@tonic-gate		off = dirp->loc & ((1 << ISO_SECTOR_SHIFT) - 1);
2967c478bdstevel@tonic-gate		if (off == 0) {
2977c478bdstevel@tonic-gate			lbn = hdbtodb(dirp->loc >> ISO_SECTOR_SHIFT);
2987c478bdstevel@tonic-gate			filep->fi_blocknum = lbn + hdbtodb(ip->i_number);
2997c478bdstevel@tonic-gate			filep->fi_count = ISO_SECTOR_SIZE;
3007c478bdstevel@tonic-gate			/* check the block cache */
3017c478bdstevel@tonic-gate			if ((filep->fi_memp = get_bcache(filep)) == 0)
3027c478bdstevel@tonic-gate				if (set_bcache(filep))
3037c478bdstevel@tonic-gate					return ((struct hs_direct *)-1);
3047c478bdstevel@tonic-gate		}
3057c478bdstevel@tonic-gate		dirp->loc += parse_dir(filep, off, &hsdep);
3067c478bdstevel@tonic-gate		if (udp->d_reclen == 0 && dirp->loc <= ip->i_size) {
3077c478bdstevel@tonic-gate			dirp->loc = roundup(dirp->loc, ISO_SECTOR_SIZE);
3087c478bdstevel@tonic-gate			continue;
3097c478bdstevel@tonic-gate		}
3107c478bdstevel@tonic-gate		return (&hsdep);
3117c478bdstevel@tonic-gate	}
3127c478bdstevel@tonic-gate}
3137c478bdstevel@tonic-gate
3147c478bdstevel@tonic-gate/*
3157c478bdstevel@tonic-gate * Get the next block of data from the file.  If possible, dma right into
3167c478bdstevel@tonic-gate * user's buffer
3177c478bdstevel@tonic-gate */
3187c478bdstevel@tonic-gatestatic int
3197c478bdstevel@tonic-gategetblock(fileid_t *filep, caddr_t buf, int count, int *rcount)
3207c478bdstevel@tonic-gate{
3217c478bdstevel@tonic-gate	register struct inode *ip;
3227c478bdstevel@tonic-gate	register caddr_t p;
3237c478bdstevel@tonic-gate	register int off, size, diff;
3247c478bdstevel@tonic-gate	register daddr_t lbn;
3257c478bdstevel@tonic-gate	static int	pos;
3267c478bdstevel@tonic-gate	static char 	ind[] = "|/-\\";	/* that's entertainment? */
3277c478bdstevel@tonic-gate	static int	blks_read;
3287c478bdstevel@tonic-gate
3297c478bdstevel@tonic-gate	ip = filep->fi_inode;
3307c478bdstevel@tonic-gate	p = filep->fi_memp;
3317c478bdstevel@tonic-gate	if ((signed)filep->fi_count <= 0) {
3327c478bdstevel@tonic-gate
3337c478bdstevel@tonic-gate		/* find the amt left to be read in the file */
3347c478bdstevel@tonic-gate		diff = ip->i_size - filep->fi_offset;
3357c478bdstevel@tonic-gate		if (diff <= 0) {
3367c478bdstevel@tonic-gate			printf("Short read\n");
3377c478bdstevel@tonic-gate			return (-1);
3387c478bdstevel@tonic-gate		}
3397c478bdstevel@tonic-gate
3407c478bdstevel@tonic-gate		/* which block (or frag) in the file do we read? */
3417c478bdstevel@tonic-gate		lbn = hdbtodb(filep->fi_offset >> ISO_SECTOR_SHIFT);
3427c478bdstevel@tonic-gate
3437c478bdstevel@tonic-gate		/* which physical block on the device do we read? */
3447c478bdstevel@tonic-gate		filep->fi_blocknum = lbn + hdbtodb(ip->i_number);
3457c478bdstevel@tonic-gate
3467c478bdstevel@tonic-gate		off = filep->fi_offset & ((1 << ISO_SECTOR_SHIFT) - 1);
3477c478bdstevel@tonic-gate
3487c478bdstevel@tonic-gate		size = sizeof (filep->fi_buf);
3497c478bdstevel@tonic-gate		if (size > ISO_SECTOR_SIZE)
3507c478bdstevel@tonic-gate			size = ISO_SECTOR_SIZE;
3517c478bdstevel@tonic-gate
3527c478bdstevel@tonic-gate		filep->fi_count = size;
3537c478bdstevel@tonic-gate		filep->fi_memp = filep->fi_buf;
3547c478bdstevel@tonic-gate
3557c478bdstevel@tonic-gate		/*
3567c478bdstevel@tonic-gate		 * optimization if we are reading large blocks of data then
3577c478bdstevel@tonic-gate		 * we can go directly to user's buffer
3587c478bdstevel@tonic-gate		 */
3597c478bdstevel@tonic-gate		*rcount = 0;
3607c478bdstevel@tonic-gate		if (off == 0 && count >= size) {
3617c478bdstevel@tonic-gate			filep->fi_memp = buf;
3627c478bdstevel@tonic-gate			if (diskread(filep)) {
3637c478bdstevel@tonic-gate				return (-1);
3647c478bdstevel@tonic-gate			}
3657c478bdstevel@tonic-gate			*rcount = size;
3667c478bdstevel@tonic-gate			filep->fi_count = 0;
3677c478bdstevel@tonic-gate			read_opt++;
3687c478bdstevel@tonic-gate			if ((blks_read++ & 0x3) == 0)
3697c478bdstevel@tonic-gate				printf("%c\b", ind[pos++ & 3]);
3707c478bdstevel@tonic-gate			return (0);
3717c478bdstevel@tonic-gate		} else
3727c478bdstevel@tonic-gate			if (diskread(filep))
3737c478bdstevel@tonic-gate				return (-1);
3747c478bdstevel@tonic-gate
3757c478bdstevel@tonic-gate		/*
3767c478bdstevel@tonic-gate		 * round and round she goes (though not on every block..
3777c478bdstevel@tonic-gate		 * - OBP's take a fair bit of time to actually print stuff)
3787c478bdstevel@tonic-gate		 */
3797c478bdstevel@tonic-gate		if ((blks_read++ & 0x3) == 0)
3807c478bdstevel@tonic-gate			printf("%c\b", ind[pos++ & 3]);
3817c478bdstevel@tonic-gate
3827c478bdstevel@tonic-gate		if (filep->fi_offset - off + size >= ip->i_size)
3837c478bdstevel@tonic-gate			filep->fi_count = diff + off;
3847c478bdstevel@tonic-gate		filep->fi_count -= off;
3857c478bdstevel@tonic-gate		p = &filep->fi_memp[off];
3867c478bdstevel@tonic-gate	}
3877c478bdstevel@tonic-gate	filep->fi_memp = p;
3887c478bdstevel@tonic-gate	return (0);
3897c478bdstevel@tonic-gate}
3907c478bdstevel@tonic-gate
3917c478bdstevel@tonic-gate
3927c478bdstevel@tonic-gate/*
3937c478bdstevel@tonic-gate *  This is the high-level read function.  It works like this.
3947c478bdstevel@tonic-gate *  We assume that our IO device buffers up some amount of
3957c478bdstevel@tonic-gate *  data ant that we can get a ptr to it.  Thus we need
3967c478bdstevel@tonic-gate *  to actually call the device func about filesize/blocksize times
3977c478bdstevel@tonic-gate *  and this greatly increases our IO speed.  When we already
3987c478bdstevel@tonic-gate *  have data in the buffer, we just return that data (with bcopy() ).
3997c478bdstevel@tonic-gate */
4007c478bdstevel@tonic-gate
4017c478bdstevel@tonic-gatestatic ssize_t
4027c478bdstevel@tonic-gateboot_hsfs_read(int fd, caddr_t buf, size_t count)
4037c478bdstevel@tonic-gate{
4047c478bdstevel@tonic-gate	size_t i, j;
4057c478bdstevel@tonic-gate	struct inode *ip;
4067c478bdstevel@tonic-gate	caddr_t	n;
4077c478bdstevel@tonic-gate	fileid_t *filep;
4087c478bdstevel@tonic-gate	int rcount;
4097c478bdstevel@tonic-gate
4107c478bdstevel@tonic-gate	if (!(filep = find_fp(fd))) {
4117c478bdstevel@tonic-gate		return (-1);
4127c478bdstevel@tonic-gate	}
4137c478bdstevel@tonic-gate
4147c478bdstevel@tonic-gate	ip = filep->fi_inode;
4157c478bdstevel@tonic-gate
4167c478bdstevel@tonic-gate	if (filep->fi_offset + count > ip->i_size)
4177c478bdstevel@tonic-gate		count = ip->i_size - filep->fi_offset;
4187c478bdstevel@tonic-gate
4197c478bdstevel@tonic-gate	/* that was easy */
4207c478bdstevel@tonic-gate	if ((i = count) == 0)
4217c478bdstevel@tonic-gate		return (0);
4227c478bdstevel@tonic-gate
4237c478bdstevel@tonic-gate	n = buf;
4247c478bdstevel@tonic-gate	while (i > 0) {
4257c478bdstevel@tonic-gate		/* If we need to reload the buffer, do so */
4267c478bdstevel@tonic-gate		if ((j = filep->fi_count) == 0) {
4277c478bdstevel@tonic-gate			getblock(filep, buf, i, &rcount);
4287c478bdstevel@tonic-gate			i -= rcount;
4297c478bdstevel@tonic-gate			buf += rcount;
4307c478bdstevel@tonic-gate			filep->fi_offset += rcount;
4317c478bdstevel@tonic-gate		} else {
4327c478bdstevel@tonic-gate			/* else just bcopy from our buffer */
4337c478bdstevel@tonic-gate			j = MIN(i, j);
4347c478bdstevel@tonic-gate			bcopy(filep->fi_memp, buf, (unsigned)j);
4357c478bdstevel@tonic-gate			buf += j;
4367c478bdstevel@tonic-gate			filep->fi_memp += j;
4377c478bdstevel@tonic-gate			filep->fi_offset += j;
4387c478bdstevel@tonic-gate			filep->fi_count -= j;
4397c478bdstevel@tonic-gate			i -= j;
4407c478bdstevel@tonic-gate		}
4417c478bdstevel@tonic-gate	}
4427c478bdstevel@tonic-gate	return (buf - n);
4437c478bdstevel@tonic-gate}
4447c478bdstevel@tonic-gate
4457c478bdstevel@tonic-gate/*
4467c478bdstevel@tonic-gate *	This routine will open a device as it is known by the
4477c478bdstevel@tonic-gate *	V2 OBP.
4487c478bdstevel@tonic-gate *	Interface Defn:
4497c478bdstevel@tonic-gate *	err = mountroot(string);
4507c478bdstevel@tonic-gate *	err:	0 on success
4517c478bdstevel@tonic-gate *		-1 on failure
4527c478bdstevel@tonic-gate *	string:	char string describing the properties of the device.
4537c478bdstevel@tonic-gate *	We must not dork with any fi[]'s here.  Save that for later.
4547c478bdstevel@tonic-gate */
4557c478bdstevel@tonic-gate
4567c478bdstevel@tonic-gatestatic int
4577c478bdstevel@tonic-gateboot_hsfs_mountroot(char *str)
4587c478bdstevel@tonic-gate{
4597c478bdstevel@tonic-gate	ihandle_t	h;
4607c478bdstevel@tonic-gate	struct hs_volume *fsp;
4617c478bdstevel@tonic-gate	char 		*bufp;
4627c478bdstevel@tonic-gate
4637c478bdstevel@tonic-gate	if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE))
464986fd29setje		printf("mountroot()\n");
4657c478bdstevel@tonic-gate
4667c478bdstevel@tonic-gate	/*
4677c478bdstevel@tonic-gate	 * If already mounted, just return success.
4687c478bdstevel@tonic-gate	 */
4697c478bdstevel@tonic-gate	if (root_ino != 0) {
4707c478bdstevel@tonic-gate		return (0);
4717c478bdstevel@tonic-gate	}
4727c478bdstevel@tonic-gate
4737c478bdstevel@tonic-gate	h = prom_open(str);
4747c478bdstevel@tonic-gate
4757c478bdstevel@tonic-gate	if (h == 0) {
4767c478bdstevel@tonic-gate		printf("Cannot open %s\n", str);
4777c478bdstevel@tonic-gate		return (-1);
4787c478bdstevel@tonic-gate	}
4797c478bdstevel@tonic-gate
4807c478bdstevel@tonic-gate	devp = (devid_t *)bkmem_alloc(sizeof (devid_t));
4817c478bdstevel@tonic-gate	devp->di_taken = 1;
4827c478bdstevel@tonic-gate	devp->di_dcookie = h;
4837c478bdstevel@tonic-gate	devp->di_desc = (char *)bkmem_alloc(strlen(str) + 1);
4847c478bdstevel@tonic-gate	(void) strcpy(devp->di_desc, str);
4857c478bdstevel@tonic-gate	bzero(devp->un_fs.dummy, sizeof (devp->un_fs.dummy));
4867c478bdstevel@tonic-gate	head = (fileid_t *)bkmem_alloc(sizeof (fileid_t));
4877c478bdstevel@tonic-gate	head->fi_back = head->fi_forw = head;
4887c478bdstevel@tonic-gate	head->fi_filedes = 0;
4897c478bdstevel@tonic-gate	head->fi_taken = 0;
4907c478bdstevel@tonic-gate
4917c478bdstevel@tonic-gate	/* Setup read of the "superblock" */
4927c478bdstevel@tonic-gate	bzero(head->fi_buf, sizeof (head->fi_buf));
4937c478bdstevel@tonic-gate	head->fi_devp = devp;
4947c478bdstevel@tonic-gate	head->fi_blocknum = hdbtodb(ISO_VOLDESC_SEC);
4957c478bdstevel@tonic-gate	head->fi_count = ISO_SECTOR_SIZE;
4967c478bdstevel@tonic-gate	head->fi_memp = head->fi_buf;
4977c478bdstevel@tonic-gate	head->fi_offset = 0;
4987c478bdstevel@tonic-gate
4997c478bdstevel@tonic-gate	if (diskread(head)) {
5007c478bdstevel@tonic-gate		printf("mountroot(): read super block failed!\n");
5017c478bdstevel@tonic-gate		boot_hsfs_closeall(1);
5027c478bdstevel@tonic-gate		return (-1);
5037c478bdstevel@tonic-gate	}
5047c478bdstevel@tonic-gate
5057c478bdstevel@tonic-gate	bufp = head->fi_memp;
5067c478bdstevel@tonic-gate	fsp = (struct hs_volume *)devp->un_fs.dummy;
5077c478bdstevel@tonic-gate	/* Since RRIP is based on ISO9660, that's where we start */
5087c478bdstevel@tonic-gate
5097c478bdstevel@tonic-gate	if (ISO_DESC_TYPE(bufp) != ISO_VD_PVD ||
5107c478bdstevel@tonic-gate	    strncmp((char *)(ISO_std_id(bufp)), (char *)(ISO_ID_STRING),
5117c478bdstevel@tonic-gate	    ISO_ID_STRLEN) != 0 || ISO_STD_VER(bufp) != ISO_ID_VER) {
5127c478bdstevel@tonic-gate		boot_hsfs_closeall(1);
5137c478bdstevel@tonic-gate		return (-1);
5147c478bdstevel@tonic-gate	}
5157c478bdstevel@tonic-gate
5167c478bdstevel@tonic-gate	/* Now we fill in the volume descriptor */
5177c478bdstevel@tonic-gate	fsp->vol_size = ISO_VOL_SIZE(bufp);
5187c478bdstevel@tonic-gate	fsp->lbn_size = ISO_BLK_SIZE(bufp);
5197c478bdstevel@tonic-gate	fsp->lbn_shift = ISO_SECTOR_SHIFT;
5207c478bdstevel@tonic-gate	fsp->lbn_secshift = ISO_SECTOR_SHIFT;
5217c478bdstevel@tonic-gate	fsp->vol_set_size = (ushort_t)ISO_SET_SIZE(bufp);
5227c478bdstevel@tonic-gate	fsp->vol_set_seq = (ushort_t)ISO_SET_SEQ(bufp);
5237c478bdstevel@tonic-gate
5247c478bdstevel@tonic-gate	/* Make sure we have a valid logical block size */
5257c478bdstevel@tonic-gate	if (fsp->lbn_size & ~(1 << fsp->lbn_shift)) {
5267c478bdstevel@tonic-gate		printf("%d byte logical block size invalid.\n", fsp->lbn_size);
5277c478bdstevel@tonic-gate		boot_hsfs_closeall(1);
5287c478bdstevel@tonic-gate		return (-1);
5297c478bdstevel@tonic-gate	}
5307c478bdstevel@tonic-gate
5317c478bdstevel@tonic-gate	/* Since an HSFS root could be located anywhere on the media! */
5327c478bdstevel@tonic-gate	root_ino = IDE_EXT_LBN(ISO_root_dir(bufp));
5337c478bdstevel@tonic-gate
5347c478bdstevel@tonic-gate	if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE)) {
5357c478bdstevel@tonic-gate		int	i;
5367c478bdstevel@tonic-gate
5377c478bdstevel@tonic-gate		printf("root_ino=%d\n", root_ino);
5387c478bdstevel@tonic-gate		printf("ID=");
5397c478bdstevel@tonic-gate		for (i = 0; i < ISO_ID_STRLEN; i++)
5407c478bdstevel@tonic-gate			printf("%c", *(ISO_std_id(bufp)+i));
5417c478bdstevel@tonic-gate		printf(" VS=%d\n", fsp->vol_size);
5427c478bdstevel@tonic-gate	}
5437c478bdstevel@tonic-gate
5447c478bdstevel@tonic-gate	return (0);
5457c478bdstevel@tonic-gate}
5467c478bdstevel@tonic-gate
5477c478bdstevel@tonic-gate/*
5487c478bdstevel@tonic-gate * Unmount the currently mounted root fs.  In practice, this means
5497c478bdstevel@tonic-gate * closing all open files and releasing resources.  All of this
5507c478bdstevel@tonic-gate * is done by boot_hsfs_closeall().
5517c478bdstevel@tonic-gate */
5527c478bdstevel@tonic-gate
5537c478bdstevel@tonic-gateint
5547c478bdstevel@tonic-gateboot_hsfs_unmountroot(void)
5557c478bdstevel@tonic-gate{
5567c478bdstevel@tonic-gate	if (root_ino == 0)
5577c478bdstevel@tonic-gate		return (-1);
5587c478bdstevel@tonic-gate
5597c478bdstevel@tonic-gate	boot_hsfs_closeall(1);
5607c478bdstevel@tonic-gate
5617c478bdstevel@tonic-gate	return (0);
5627c478bdstevel@tonic-gate}
5637c478bdstevel@tonic-gate
5647c478bdstevel@tonic-gate/*
5657c478bdstevel@tonic-gate *	We allocate an fd here for use when talking
5667c478bdstevel@tonic-gate *	to the file itself.
5677c478bdstevel@tonic-gate */
5687c478bdstevel@tonic-gate
5697c478bdstevel@tonic-gate/*ARGSUSED*/
5707c478bdstevel@tonic-gatestatic int
5717c478bdstevel@tonic-gateboot_hsfs_open(char *filename, int flags)
5727c478bdstevel@tonic-gate{
5737c478bdstevel@tonic-gate	fileid_t	*filep;
5747c478bdstevel@tonic-gate	ino_t		inode;
5757c478bdstevel@tonic-gate	static int	filedes = 1;
5767c478bdstevel@tonic-gate
5777c478bdstevel@tonic-gate	/* build and link a new file descriptor */
5787c478bdstevel@tonic-gate	filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t));
5797c478bdstevel@tonic-gate	filep->fi_back = head->fi_back;
5807c478bdstevel@tonic-gate	filep->fi_forw = head;
5817c478bdstevel@tonic-gate	head->fi_back->fi_forw = filep;
5827c478bdstevel@tonic-gate	head->fi_back = filep;
5837c478bdstevel@tonic-gate
5847c478bdstevel@tonic-gate	filep->fi_filedes = filedes++;
5857c478bdstevel@tonic-gate	filep->fi_taken = 1;
5867c478bdstevel@tonic-gate	filep->fi_path = (char *)bkmem_alloc(strlen(filename) + 1);
5877c478bdstevel@tonic-gate	(void) strcpy(filep->fi_path, filename);
5887c478bdstevel@tonic-gate	filep->fi_devp = devp; /* dev is already "mounted" */
5897c478bdstevel@tonic-gate
5907c478bdstevel@tonic-gate	filep->fi_inode = 0;
5917c478bdstevel@tonic-gate
5927c478bdstevel@tonic-gate	inode = find(filep, filename);
5937c478bdstevel@tonic-gate	if (inode == (ino_t)0) {
5947c478bdstevel@tonic-gate		if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE))
595986fd29setje			printf("open(%s) ENOENT\n", filename);
5967c478bdstevel@tonic-gate		(void) boot_hsfs_close(filep->fi_filedes);
5977c478bdstevel@tonic-gate		return (-1);
5987c478bdstevel@tonic-gate	}
5997c478bdstevel@tonic-gate
6007c478bdstevel@tonic-gate	filep->fi_blocknum = hdbtodb(inode);
6017c478bdstevel@tonic-gate	filep->fi_offset = filep->fi_count = 0;
6027c478bdstevel@tonic-gate
6037c478bdstevel@tonic-gate	if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE))
604986fd29setje		printf("open(%s) fd=%d\n", filename, filep->fi_filedes);
6057c478bdstevel@tonic-gate	return (filep->fi_filedes);
6067c478bdstevel@tonic-gate}
6077c478bdstevel@tonic-gate
6087c478bdstevel@tonic-gate/*
6097c478bdstevel@tonic-gate * hsfs_fstat() only supports size, mode and times at present time.
6107c478bdstevel@tonic-gate */
6117c478bdstevel@tonic-gate
6127c478bdstevel@tonic-gatestatic int
6137c478bdstevel@tonic-gateboot_hsfs_fstat(int fd, struct bootstat *stp)
6147c478bdstevel@tonic-gate{
6157c478bdstevel@tonic-gate	fileid_t	*filep;
6167c478bdstevel@tonic-gate	struct inode	*ip;
6177c478bdstevel@tonic-gate
6187c478bdstevel@tonic-gate	if (!(filep = find_fp(fd)))
6197c478bdstevel@tonic-gate		return (-1);
6207c478bdstevel@tonic-gate
6217c478bdstevel@tonic-gate	ip = filep->fi_inode;
6227c478bdstevel@tonic-gate
6237c478bdstevel@tonic-gate	stp->st_mode = 0;
6247c478bdstevel@tonic-gate	stp->st_size = 0;
6257c478bdstevel@tonic-gate
6267c478bdstevel@tonic-gate	if (ip == NULL)
6277c478bdstevel@tonic-gate		return (0);
6287c478bdstevel@tonic-gate
6297c478bdstevel@tonic-gate	switch (ip->i_smode & IFMT) {
6307c478bdstevel@tonic-gate	case IFDIR:
6317c478bdstevel@tonic-gate		stp->st_mode = S_IFDIR;
6327c478bdstevel@tonic-gate		break;
6337c478bdstevel@tonic-gate	case IFREG:
6347c478bdstevel@tonic-gate		stp->st_mode = S_IFREG;
6357c478bdstevel@tonic-gate		break;
6367c478bdstevel@tonic-gate	default:
6377c478bdstevel@tonic-gate		break;
6387c478bdstevel@tonic-gate	}
6397c478bdstevel@tonic-gate	stp->st_size = ip->i_size;
6407c478bdstevel@tonic-gate
6417c478bdstevel@tonic-gate	/* file times */
6427c478bdstevel@tonic-gate	stp->st_atim.tv_sec = ip->i_atime.tv_sec;
6437c478bdstevel@tonic-gate	stp->st_atim.tv_nsec = ip->i_atime.tv_usec * 1000;
6447c478bdstevel@tonic-gate	stp->st_mtim.tv_sec = ip->i_mtime.tv_sec;
6457c478bdstevel@tonic-gate	stp->st_mtim.tv_nsec = ip->i_mtime.tv_usec * 1000;
6467c478bdstevel@tonic-gate	stp->st_ctim.tv_sec = ip->i_ctime.tv_sec;
6477c478bdstevel@tonic-gate	stp->st_ctim.tv_nsec = ip->i_ctime.tv_usec * 1000;
6487c478bdstevel@tonic-gate
6497c478bdstevel@tonic-gate	return (0);
6507c478bdstevel@tonic-gate}
6517c478bdstevel@tonic-gate
6527c478bdstevel@tonic-gate/*
6537c478bdstevel@tonic-gate *  We don't do any IO here.
6547c478bdstevel@tonic-gate *  We just play games with the device pointers.
6557c478bdstevel@tonic-gate */
6567c478bdstevel@tonic-gate
6577c478bdstevel@tonic-gate/*ARGSUSED*/
6587c478bdstevel@tonic-gatestatic off_t
6597c478bdstevel@tonic-gateboot_hsfs_lseek(int fd, off_t addr, int whence)
6607c478bdstevel@tonic-gate{
6617c478bdstevel@tonic-gate	fileid_t *filep;
6627c478bdstevel@tonic-gate
6637c478bdstevel@tonic-gate	if (!(filep = find_fp(fd)))
6647c478bdstevel@tonic-gate		return (-1);
6657c478bdstevel@tonic-gate
6667c478bdstevel@tonic-gate	filep->fi_offset = addr;
6677c478bdstevel@tonic-gate	filep->fi_blocknum = addr / DEV_BSIZE;
6687c478bdstevel@tonic-gate	filep->fi_count = 0;
6697c478bdstevel@tonic-gate
6707c478bdstevel@tonic-gate	return (0);
6717c478bdstevel@tonic-gate}
6727c478bdstevel@tonic-gate
6737c478bdstevel@tonic-gatestatic int
6747c478bdstevel@tonic-gateboot_hsfs_close(int fd)
6757c478bdstevel@tonic-gate{
6767c478bdstevel@tonic-gate	fileid_t *filep;
6777c478bdstevel@tonic-gate
6787c478bdstevel@tonic-gate	if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE))
679986fd29setje		printf("close(%d)\n", fd);
6807c478bdstevel@tonic-gate
6817c478bdstevel@tonic-gate	if (filep = find_fp(fd)) {
6827c478bdstevel@tonic-gate		/* Clear the ranks */
6837c478bdstevel@tonic-gate		bkmem_free(filep->fi_path, strlen(filep->fi_path)+1);
6847c478bdstevel@tonic-gate		filep->fi_blocknum = filep->fi_count = filep->fi_offset = 0;
6857c478bdstevel@tonic-gate		filep->fi_memp = (caddr_t)0;
6867c478bdstevel@tonic-gate		filep->fi_devp = 0;
6877c478bdstevel@tonic-gate		filep->fi_taken = 0;
6887c478bdstevel@tonic-gate
6897c478bdstevel@tonic-gate		/* unlink and deallocate node */
6907c478bdstevel@tonic-gate		filep->fi_forw->fi_back = filep->fi_back;
6917c478bdstevel@tonic-gate		filep->fi_back->fi_forw = filep->fi_forw;
6927c478bdstevel@tonic-gate		bkmem_free((char *)filep, sizeof (fileid_t));
6937c478bdstevel@tonic-gate
6947c478bdstevel@tonic-gate		return (0);
6957c478bdstevel@tonic-gate	} else {
6967c478bdstevel@tonic-gate		/* Big problem */
6977c478bdstevel@tonic-gate		printf("\nFile descrip %d not allocated!", fd);
6987c478bdstevel@tonic-gate		return (-1);
6997c478bdstevel@tonic-gate	}
7007c478bdstevel@tonic-gate}
7017c478bdstevel@tonic-gate
702986fd29setje/* closeall is now idempotent */
7037c478bdstevel@tonic-gate/*ARGSUSED*/
7047c478bdstevel@tonic-gatestatic void
7057c478bdstevel@tonic-gateboot_hsfs_closeall(int flag)
7067c478bdstevel@tonic-gate{
7077c478bdstevel@tonic-gate	fileid_t	*filep = head;
7087c478bdstevel@tonic-gate	extern int verbosemode;
7097c478bdstevel@tonic-gate
710986fd29setje	if (devp == NULL) {
711986fd29setje		if (head)
712986fd29setje			prom_panic("boot_hsfs_closeall: head != NULL.\n");
713986fd29setje		return;
714986fd29setje	}
715986fd29setje
7167c478bdstevel@tonic-gate	while ((filep = filep->fi_forw) != head)
7177c478bdstevel@tonic-gate		if (filep->fi_taken)
7187c478bdstevel@tonic-gate			if (boot_hsfs_close(filep->fi_filedes))
7197c478bdstevel@tonic-gate				prom_panic("Filesystem may be inconsistent.\n");
7207c478bdstevel@tonic-gate
721986fd29setje
7227c478bdstevel@tonic-gate	release_cache(devp->di_dcookie);
7237c478bdstevel@tonic-gate	(void) prom_close(devp->di_dcookie);
7247c478bdstevel@tonic-gate	devp->di_taken = 0;
7257c478bdstevel@tonic-gate	if (verbosemode)
7267c478bdstevel@tonic-gate		print_cache_data();
7277c478bdstevel@tonic-gate	bkmem_free((char *)devp, sizeof (devid_t));
7287c478bdstevel@tonic-gate	bkmem_free((char *)head, sizeof (fileid_t));
7297c478bdstevel@tonic-gate	root_ino = 0;
730986fd29setje	devp = NULL;
731986fd29setje	head = NULL;
7327c478bdstevel@tonic-gate}
7337c478bdstevel@tonic-gate
7347c478bdstevel@tonic-gatestatic uint_t
7357c478bdstevel@tonic-gateparse_dir(fileid_t *filep, int offset, struct hs_direct *hsdep)
7367c478bdstevel@tonic-gate{
7377c478bdstevel@tonic-gate	char *bufp = (char *)(filep->fi_memp + offset);
7387c478bdstevel@tonic-gate	struct direct *udp = &hsdep->hs_ufs_dir;
7397c478bdstevel@tonic-gate	struct hs_direntry *hdp = &hsdep->hs_dir;
7407c478bdstevel@tonic-gate	uint_t ce_lbn;
7417c478bdstevel@tonic-gate	uint_t ce_len;
7427c478bdstevel@tonic-gate	uint_t nmlen;
7437c478bdstevel@tonic-gate	uint_t i;
7447c478bdstevel@tonic-gate	uchar_t c;
7457c478bdstevel@tonic-gate	int ret_code = 0;
7467c478bdstevel@tonic-gate
7477c478bdstevel@tonic-gate	if ((udp->d_reclen = IDE_DIR_LEN(bufp)) == 0)
7487c478bdstevel@tonic-gate		return (0);
7497c478bdstevel@tonic-gate
7507c478bdstevel@tonic-gate	hdp->ext_lbn  = IDE_EXT_LBN(bufp);
7517c478bdstevel@tonic-gate	hdp->ext_size = IDE_EXT_SIZE(bufp);
7527c478bdstevel@tonic-gate	hs_dodates(HS_VOL_TYPE_ISO, hdp, bufp);
7537c478bdstevel@tonic-gate	hdp->xar_len  = IDE_XAR_LEN(bufp);
7547c478bdstevel@tonic-gate	hdp->intlf_sz = IDE_INTRLV_SIZE(bufp);
7557c478bdstevel@tonic-gate	hdp->intlf_sk = IDE_INTRLV_SKIP(bufp);
7567c478bdstevel@tonic-gate	hdp->sym_link = NULL;
7577c478bdstevel@tonic-gate
7587c478bdstevel@tonic-gate	udp->d_ino = hdp->ext_lbn;
7597c478bdstevel@tonic-gate
7607c478bdstevel@tonic-gate	c = IDE_FLAGS(bufp);
7617c478bdstevel@tonic-gate	if (IDE_REGULAR_FILE(c)) {
7627c478bdstevel@tonic-gate		hdp->type = VREG;
7637c478bdstevel@tonic-gate		hdp->mode = IFREG;
7647c478bdstevel@tonic-gate		hdp->nlink = 1;
7657c478bdstevel@tonic-gate	} else if (IDE_REGULAR_DIR(c)) {
7667c478bdstevel@tonic-gate		hdp->type = VDIR;
7677c478bdstevel@tonic-gate		hdp->mode = IFDIR;
7687c478bdstevel@tonic-gate		hdp->nlink = 2;
7697c478bdstevel@tonic-gate	} else {
7707c478bdstevel@tonic-gate		printf("parse_dir(): file type=0x%x unknown.\n", c);
7717c478bdstevel@tonic-gate		return ((uint_t)-1);
7727c478bdstevel@tonic-gate	}
7737c478bdstevel@tonic-gate
7747c478bdstevel@tonic-gate	/* Some initial conditions */
7757c478bdstevel@tonic-gate	nmlen = IDE_NAME_LEN(bufp);
7767c478bdstevel@tonic-gate	c = *IDE_NAME(bufp);
7777c478bdstevel@tonic-gate	/* Special Case: Current Directory */
7787c478bdstevel@tonic-gate	if (nmlen == 1 && c == '\0') {
7797c478bdstevel@tonic-gate		udp->d_name[0] = '.';
7807c478bdstevel@tonic-gate		udp->d_name[1] = '\0';
7817c478bdstevel@tonic-gate		udp->d_namlen = 1;
7827c478bdstevel@tonic-gate	/* Special Case: Parent Directory */
7837c478bdstevel@tonic-gate	} else if (nmlen == 1 && c == '\001') {
7847c478bdstevel@tonic-gate		udp->d_name[0] = '.';
7857c478bdstevel@tonic-gate		udp->d_name[1] = '.';
7867c478bdstevel@tonic-gate		udp->d_name[2] = '\0';
7877c478bdstevel@tonic-gate		udp->d_namlen = 2;
7887c478bdstevel@tonic-gate	/* Other file name */
7897c478bdstevel@tonic-gate	} else {
7907c478bdstevel@tonic-gate		udp->d_namlen = 0;
7917c478bdstevel@tonic-gate		for (i = 0; i < nmlen; i++) {
7927c478bdstevel@tonic-gate			c = *(IDE_name(bufp)+i);
7937c478bdstevel@tonic-gate			if (c == ';')
7947c478bdstevel@tonic-gate				break;
7957c478bdstevel@tonic-gate			else if (c == ' ')
7967c478bdstevel@tonic-gate				continue;
7977c478bdstevel@tonic-gate			else
7987c478bdstevel@tonic-gate				udp->d_name[udp->d_namlen++] = c;
7997c478bdstevel@tonic-gate		}
8007c478bdstevel@tonic-gate		udp->d_name[udp->d_namlen] = '\0';
8017c478bdstevel@tonic-gate	}
8027c478bdstevel@tonic-gate	/* System Use Fields */
8037c478bdstevel@tonic-gate	ce_len = IDE_SUA_LEN(bufp);
8047c478bdstevel@tonic-gate	ce_lbn = 0;
8057c478bdstevel@tonic-gate	if ((int)(ce_len) > 0) {
806986fd29setje		ce_lbn = parse_susp((char *)IDE_sys_use_area(bufp),
807986fd29setje		    &ce_len, hsdep);
808986fd29setje		while (ce_lbn) {
809986fd29setje			daddr_t save_blocknum = filep->fi_blocknum;
810986fd29setje			daddr_t save_offset = filep->fi_offset;
811986fd29setje			caddr_t save_memp = filep->fi_memp;
812986fd29setje			uint_t save_count = filep->fi_count;
8137c478bdstevel@tonic-gate
8147c478bdstevel@tonic-gate#ifdef	noisy
815986fd29setje			print_io_req(filep, "parse_dir(): [I]");
8167c478bdstevel@tonic-gate#endif	/* noisy */
8177c478bdstevel@tonic-gate
818986fd29setje			filep->fi_blocknum = hdbtodb(ce_lbn);
819986fd29setje			filep->fi_offset = 0;
820986fd29setje			filep->fi_count = ISO_SECTOR_SIZE;
8217c478bdstevel@tonic-gate
8227c478bdstevel@tonic-gate#ifdef	noisy
823986fd29setje			print_io_req(filep, "parse_dir(): [0]");
8247c478bdstevel@tonic-gate#endif	/* noisy */
8257c478bdstevel@tonic-gate
826986fd29setje			if ((filep->fi_memp = get_bcache(filep)) == 0)
827986fd29setje				ret_code = set_bcache(filep);
8287c478bdstevel@tonic-gate
8297c478bdstevel@tonic-gate#ifdef	noisy
830986fd29setje			print_io_req(filep, "parse_dir(): [1]");
8317c478bdstevel@tonic-gate#endif	/* noisy */
8327c478bdstevel@tonic-gate
833986fd29setje			if (ret_code) {
834986fd29setje				filep->fi_blocknum = save_blocknum;
835986fd29setje				filep->fi_offset = save_offset;
836986fd29setje				filep->fi_memp = save_memp;
837986fd29setje				filep->fi_count = save_count;
838986fd29setje				printf("parse_dir(): "
839986fd29setje				    "set_bcache() failed (%d)\n", ret_code);
840986fd29setje				break;
841986fd29setje			}
842986fd29setje			ce_lbn = parse_susp(filep->fi_memp, &ce_len, hsdep);
843986fd29setje
844986fd29setje			filep->fi_blocknum = save_blocknum;
845986fd29setje			filep->fi_offset = save_offset;
846986fd29setje			filep->fi_memp = save_memp;
847986fd29setje			filep->fi_count = save_count;
8487c478bdstevel@tonic-gate
8497c478bdstevel@tonic-gate#ifdef	noisy
850986fd29setje			print_io_req(filep, "parse_dir(): [2]");
8517c478bdstevel@tonic-gate#endif	/* noisy */
852986fd29setje		}
8537c478bdstevel@tonic-gate	}
8547c478bdstevel@tonic-gate
8557c478bdstevel@tonic-gate	return (udp->d_reclen);
8567c478bdstevel@tonic-gate}
8577c478bdstevel@tonic-gate
8587c478bdstevel@tonic-gatestatic uint_t
8597c478bdstevel@tonic-gateparse_susp(char *bufp, uint_t *ce_len, struct hs_direct *hsdep)
8607c478bdstevel@tonic-gate{
8617c478bdstevel@tonic-gate	struct direct *udp = &hsdep->hs_ufs_dir;
8627c478bdstevel@tonic-gate	uchar_t *susp;
8637c478bdstevel@tonic-gate	uint_t cur_off = 0;
8647c478bdstevel@tonic-gate	uint_t blk_len = *ce_len;
8657c478bdstevel@tonic-gate	uint_t susp_len = 0;
8667c478bdstevel@tonic-gate	uint_t ce_lbn = 0;
8677c478bdstevel@tonic-gate	uint_t i;
8687c478bdstevel@tonic-gate
8697c478bdstevel@tonic-gate	while (cur_off < blk_len) {
870986fd29setje		susp = (uchar_t *)(bufp + cur_off);
871986fd29setje		if (susp[0] == '\0' || susp[1] == '\0')
872986fd29setje			break;
873986fd29setje		susp_len = SUF_LEN(susp);
874986fd29setje		if (susp_len == 0)
875986fd29setje			break;
876986fd29setje		for (i = 0; i < hsfs_num_sig; i++) {
877986fd29setje			if (strncmp(hsfs_sig_tab[i],
878986fd29setje			    (char *)susp, SUF_SIG_LEN) == 0) {
8797c478bdstevel@tonic-gate#ifdef	noisy
880986fd29setje				if ((boothowto & RB_DEBUG) &&
881986fd29setje				    (boothowto & RB_VERBOSE))
882986fd29setje					printf("  SUSP_%c%c %d\n",
883986fd29setje					    susp[0], susp[1], susp_len);
8847c478bdstevel@tonic-gate#endif	/* noisy */
885986fd29setje				switch (i) {
886986fd29setje				case SUSP_SP_IX:
887986fd29setje					if (CHECK_BYTES_OK(susp)) {
888986fd29setje						sua_offset =
889986fd29setje						    SP_SUA_OFFSET(susp);
8907c478bdstevel@tonic-gate#ifdef	lint
891986fd29setje						/* this may not be needed */
892986fd29setje						i = (int)sua_offset;
8937c478bdstevel@tonic-gate#endif	/* lint */
894986fd29setje					}
895986fd29setje					break;
8967c478bdstevel@tonic-gate
897986fd29setje				case SUSP_CE_IX:
898986fd29setje					ce_lbn = CE_BLK_LOC(susp);
899986fd29setje					*ce_len = CE_CONT_LEN(susp);
9007c478bdstevel@tonic-gate#ifdef	noisy
901986fd29setje					if ((boothowto & RB_DEBUG) &&
902986fd29setje					    (boothowto & RB_VERBOSE))
903986fd29setje						printf("parse_susp(): "
904986fd29setje						    "CE: ce_lbn = %d "
905986fd29setje						    "ce_len=%d\n",
906986fd29setje						    ce_lbn, *ce_len);
9077c478bdstevel@tonic-gate#endif	/* noisy */
908986fd29setje					break;
9097c478bdstevel@tonic-gate
910986fd29setje				case SUSP_ST_IX:
911986fd29setje					printf("parse_susp(): ST: returning "
912986fd29setje					    "%d\n", ce_lbn);
913986fd29setje					return (ce_lbn);
9147c478bdstevel@tonic-gate
915986fd29setje				case RRIP_SL_IX:
9167c478bdstevel@tonic-gate#ifdef	noisy
917986fd29setje					if ((boothowto & RB_DEBUG) &&
918986fd29setje					    (boothowto & RB_VERBOSE))
919986fd29setje						printf("parse_susp(): "
920986fd29setje						    "******* SL *******\n");
9217c478bdstevel@tonic-gate#endif	/* noisy */
922986fd29setje					break;
923986fd29setje
924