17b3700d1Sszhou /*
27b3700d1Sszhou  *  GRUB  --  GRand Unified Bootloader
37b3700d1Sszhou  *  Copyright (C) 2006 Free Software Foundation, Inc.
47b3700d1Sszhou  *
57b3700d1Sszhou  *  This program is free software; you can redistribute it and/or modify
67b3700d1Sszhou  *  it under the terms of the GNU General Public License as published by
77b3700d1Sszhou  *  the Free Software Foundation; either version 2 of the License, or
87b3700d1Sszhou  *  (at your option) any later version.
97b3700d1Sszhou  *
107b3700d1Sszhou  *  This program is distributed in the hope that it will be useful,
117b3700d1Sszhou  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
127b3700d1Sszhou  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
137b3700d1Sszhou  *  GNU General Public License for more details.
147b3700d1Sszhou  *
157b3700d1Sszhou  *  You should have received a copy of the GNU General Public License
167b3700d1Sszhou  *  along with this program; if not, write to the Free Software
177b3700d1Sszhou  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
187b3700d1Sszhou  */
197c478bd9Sstevel@tonic-gate /*
207b3700d1Sszhou  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
217c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
227c478bd9Sstevel@tonic-gate  */
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate /* From Solaris usr/src/stand/lib/fs/ufs/ufsops.c */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #ifdef	FSYS_UFS
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include "shared.h"
297c478bd9Sstevel@tonic-gate #include "filesys.h"
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include "ufs.h"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /* These are the pools of buffers, etc. */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #define SUPERBLOCK ((struct fs *)(FSYS_BUF + 0x2000))
367c478bd9Sstevel@tonic-gate #define	INODE ((struct icommon *)(FSYS_BUF + 0x1000))
377c478bd9Sstevel@tonic-gate #define DIRENT (FSYS_BUF + 0x4000)
387c478bd9Sstevel@tonic-gate #define INDIRBLK1 ((grub_daddr32_t *)(FSYS_BUF + 0x4000)) /* 2+ indir blk */
397c478bd9Sstevel@tonic-gate #define	INDIRBLK0 ((grub_daddr32_t *)(FSYS_BUF+ 0x6000))  /* 1st indirect blk */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate static int indirblk0, indirblk1;
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate static int openi(grub_ino_t);
447c478bd9Sstevel@tonic-gate static grub_ino_t dlook(grub_ino_t, char *);
457c478bd9Sstevel@tonic-gate static grub_daddr32_t sbmap(grub_daddr32_t);
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /* read superblock and check fs magic */
487c478bd9Sstevel@tonic-gate int
ufs_mount(void)497c478bd9Sstevel@tonic-gate ufs_mount(void)
507c478bd9Sstevel@tonic-gate {
517c478bd9Sstevel@tonic-gate 	if (! IS_PC_SLICE_TYPE_SOLARIS(current_slice) ||
527c478bd9Sstevel@tonic-gate 	    !devread(UFS_SBLOCK, 0, UFS_SBSIZE, (char *)SUPERBLOCK) ||
537c478bd9Sstevel@tonic-gate 	    SUPERBLOCK->fs_magic != UFS_MAGIC)
547c478bd9Sstevel@tonic-gate 		return 0;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 	return 1;
577c478bd9Sstevel@tonic-gate }
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate  * searching for a file, if successful, inode will be loaded in INODE
627c478bd9Sstevel@tonic-gate  * The entry point should really be named ufs_open(char *pathname).
637c478bd9Sstevel@tonic-gate  * For now, keep it consistent with the rest of fsys modules.
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate int
ufs_dir(char * dirname)667c478bd9Sstevel@tonic-gate ufs_dir(char *dirname)
677c478bd9Sstevel@tonic-gate {
687c478bd9Sstevel@tonic-gate 	grub_ino_t inode = ROOTINO;	/* start from root */
697c478bd9Sstevel@tonic-gate 	char *fname, ch;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	indirblk0 = indirblk1 = 0;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	/* skip leading slashes */
747c478bd9Sstevel@tonic-gate 	while (*dirname == '/')
757c478bd9Sstevel@tonic-gate 		dirname++;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 	while (inode && *dirname && !isspace(*dirname)) {
787c478bd9Sstevel@tonic-gate 		if (!openi(inode))
797c478bd9Sstevel@tonic-gate 			return 0;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 		/* parse for next path component */
827c478bd9Sstevel@tonic-gate 		fname = dirname;
837c478bd9Sstevel@tonic-gate 		while (*dirname && !isspace(*dirname) && *dirname != '/')
847c478bd9Sstevel@tonic-gate 			dirname++;
857c478bd9Sstevel@tonic-gate 		ch = *dirname;
867c478bd9Sstevel@tonic-gate 		*dirname = 0;	/* ensure null termination */
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 		inode = dlook(inode, fname);
897c478bd9Sstevel@tonic-gate 		*dirname = ch;
907c478bd9Sstevel@tonic-gate 		while (*dirname == '/')
917c478bd9Sstevel@tonic-gate 			dirname++;
927c478bd9Sstevel@tonic-gate 	}
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	/* return 1 only if inode exists and is a regular file */
957c478bd9Sstevel@tonic-gate 	if  (! openi(inode))
967c478bd9Sstevel@tonic-gate 		return (0);
977c478bd9Sstevel@tonic-gate 	filepos = 0;
987c478bd9Sstevel@tonic-gate 	filemax = INODE->ic_sizelo;
997c478bd9Sstevel@tonic-gate 	return (inode && ((INODE->ic_smode & IFMT) == IFREG));
1007c478bd9Sstevel@tonic-gate }
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * This is the high-level read function.
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate int
ufs_read(char * buf,int len)1067c478bd9Sstevel@tonic-gate ufs_read(char *buf, int len)
1077c478bd9Sstevel@tonic-gate {
10863f82aa9Sszhou   	int off, size, ret = 0, ok;
1097c478bd9Sstevel@tonic-gate 	grub_daddr32_t lblk, dblk;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate   	while (len) {
1127c478bd9Sstevel@tonic-gate 	  	off = blkoff(SUPERBLOCK, filepos);
1137c478bd9Sstevel@tonic-gate 		lblk = lblkno(SUPERBLOCK, filepos);
1147c478bd9Sstevel@tonic-gate 		size = SUPERBLOCK->fs_bsize;
1157c478bd9Sstevel@tonic-gate 		size -= off;
1167c478bd9Sstevel@tonic-gate 		if (size > len)
1177c478bd9Sstevel@tonic-gate 		  	size = len;
1187c478bd9Sstevel@tonic-gate 
1197b3700d1Sszhou 		if ((dblk = sbmap(lblk)) <= 0) {
1207b3700d1Sszhou 			/* we are in a file hole, just zero the buf */
1217b3700d1Sszhou 			grub_memset(buf, 0, size);
1227b3700d1Sszhou 		} else {
1237b3700d1Sszhou 			disk_read_func = disk_read_hook;
1247b3700d1Sszhou 			ok = devread(fsbtodb(SUPERBLOCK, dblk), off, size, buf);
1257b3700d1Sszhou 			disk_read_func = 0;
1267b3700d1Sszhou 			if (!ok)
1277b3700d1Sszhou 		  		return 0;
1287b3700d1Sszhou 		}
1297c478bd9Sstevel@tonic-gate 		buf += size;
1307c478bd9Sstevel@tonic-gate 		len -= size;
1317c478bd9Sstevel@tonic-gate 		filepos += size;
1327c478bd9Sstevel@tonic-gate 		ret += size;
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	return (ret);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate int
ufs_embed(unsigned long long * start_sector,int needed_sectors)139*2e1aefd1SJoshua M. Clulow ufs_embed (unsigned long long *start_sector, int needed_sectors)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	if (needed_sectors > 14)
1427c478bd9Sstevel@tonic-gate         	return 0;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	*start_sector = 2;
1457c478bd9Sstevel@tonic-gate 	return 1;
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /* read inode and place content in INODE */
1497c478bd9Sstevel@tonic-gate static int
openi(grub_ino_t inode)1507c478bd9Sstevel@tonic-gate openi(grub_ino_t inode)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	grub_daddr32_t dblk;
1537c478bd9Sstevel@tonic-gate 	int off;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	/* get block and byte offset into the block */
1567c478bd9Sstevel@tonic-gate 	dblk = fsbtodb(SUPERBLOCK, itod(SUPERBLOCK, inode));
1577c478bd9Sstevel@tonic-gate 	off = itoo(SUPERBLOCK, inode) * sizeof (struct icommon);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	return (devread(dblk, off, sizeof (struct icommon), (char *)INODE));
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate 
1627b3700d1Sszhou /*
1637b3700d1Sszhou  * Performs fileblock mapping. Convert file block no. to disk block no.
1647b3700d1Sszhou  * Returns 0 when block doesn't exist and <0 when block isn't initialized
1657b3700d1Sszhou  * (i.e belongs to a hole in the file).
1667b3700d1Sszhou  */
1677c478bd9Sstevel@tonic-gate grub_daddr32_t
sbmap(grub_daddr32_t bn)1687c478bd9Sstevel@tonic-gate sbmap(grub_daddr32_t bn)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate   	int level, bound, i, index;
1717c478bd9Sstevel@tonic-gate 	grub_daddr32_t nb, blkno;
1727c478bd9Sstevel@tonic-gate 	grub_daddr32_t *db = INODE->ic_db;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	/* blocks 0..UFS_NDADDR are direct blocks */
1757c478bd9Sstevel@tonic-gate 	if (bn < UFS_NDADDR) {
1767c478bd9Sstevel@tonic-gate 		return db[bn];
1777c478bd9Sstevel@tonic-gate 	}
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	/* determine how many levels of indirection. */
1807c478bd9Sstevel@tonic-gate 	level = 0;
1817c478bd9Sstevel@tonic-gate 	bn -= UFS_NDADDR;
1827c478bd9Sstevel@tonic-gate 	bound = UFS_NINDIR(SUPERBLOCK);
1837c478bd9Sstevel@tonic-gate 	while (bn >= bound) {
1847c478bd9Sstevel@tonic-gate 		level++;
1857c478bd9Sstevel@tonic-gate 		bn -= bound;
1867c478bd9Sstevel@tonic-gate 		bound *= UFS_NINDIR(SUPERBLOCK);
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate 	if (level >= UFS_NIADDR)	/* bn too big */
1897c478bd9Sstevel@tonic-gate 		return ((grub_daddr32_t)0);
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	/* fetch the first indirect block */
1927c478bd9Sstevel@tonic-gate 	nb = INODE->ic_ib[level];
1937c478bd9Sstevel@tonic-gate 	if (nb == 0) {
1947c478bd9Sstevel@tonic-gate 		return ((grub_daddr32_t)0);
1957c478bd9Sstevel@tonic-gate 	}
1967c478bd9Sstevel@tonic-gate 	if (indirblk0 != nb) {
1977c478bd9Sstevel@tonic-gate 		indirblk0 = 0;
1987c478bd9Sstevel@tonic-gate 		blkno = fsbtodb(SUPERBLOCK, nb);
1997c478bd9Sstevel@tonic-gate 		if (!devread(blkno, 0, SUPERBLOCK->fs_bsize,
2007c478bd9Sstevel@tonic-gate 		    (char *)INDIRBLK0))
2017c478bd9Sstevel@tonic-gate 			return (0);
2027c478bd9Sstevel@tonic-gate 		indirblk0 = nb;
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 	bound /= UFS_NINDIR(SUPERBLOCK);
2057c478bd9Sstevel@tonic-gate 	index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
2067c478bd9Sstevel@tonic-gate 	nb = INDIRBLK0[index];
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	/* fetch through the indirect blocks */
2097c478bd9Sstevel@tonic-gate 	for (i = 1; i <= level; i++) {
2107c478bd9Sstevel@tonic-gate 		if (indirblk1 != nb) {
2117c478bd9Sstevel@tonic-gate 			blkno = fsbtodb(SUPERBLOCK, nb);
2127c478bd9Sstevel@tonic-gate 			if (!devread(blkno, 0, SUPERBLOCK->fs_bsize,
2137c478bd9Sstevel@tonic-gate 			    (char *)INDIRBLK1))
2147c478bd9Sstevel@tonic-gate 				return (0);
2157c478bd9Sstevel@tonic-gate 			indirblk1 = nb;
2167c478bd9Sstevel@tonic-gate 		}
2177c478bd9Sstevel@tonic-gate 		bound /= UFS_NINDIR(SUPERBLOCK);
2187c478bd9Sstevel@tonic-gate 		index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
2197c478bd9Sstevel@tonic-gate 		nb = INDIRBLK1[index];
2207c478bd9Sstevel@tonic-gate 		if (nb == 0)
2217c478bd9Sstevel@tonic-gate 			return ((grub_daddr32_t)0);
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	return (nb);
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate /* search directory content for name, return inode number */
2287c478bd9Sstevel@tonic-gate static grub_ino_t
dlook(grub_ino_t dir_ino,char * name)2297c478bd9Sstevel@tonic-gate dlook(grub_ino_t dir_ino, char *name)
2307c478bd9Sstevel@tonic-gate {
2317c478bd9Sstevel@tonic-gate 	int loc, off;
2327c478bd9Sstevel@tonic-gate 	grub_daddr32_t lbn, dbn, dblk;
2337c478bd9Sstevel@tonic-gate 	struct direct *dp;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	if ((INODE->ic_smode & IFMT) != IFDIR)
2367c478bd9Sstevel@tonic-gate 		return 0;
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	loc = 0;
2397c478bd9Sstevel@tonic-gate 	while (loc < INODE->ic_sizelo) {
2407c478bd9Sstevel@tonic-gate 	  	/* offset into block */
2417c478bd9Sstevel@tonic-gate 		off = blkoff(SUPERBLOCK, loc);
2427c478bd9Sstevel@tonic-gate 		if (off == 0) {		/* need to read in a new block */
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 		  	/* get logical block number */
2457c478bd9Sstevel@tonic-gate 			lbn = lblkno(SUPERBLOCK, loc);
2467c478bd9Sstevel@tonic-gate 			/* resolve indrect blocks */
2477c478bd9Sstevel@tonic-gate 			dbn = sbmap(lbn);
2487c478bd9Sstevel@tonic-gate 			if (dbn == 0)
2497c478bd9Sstevel@tonic-gate 				return (0);
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 			dblk = fsbtodb(SUPERBLOCK, dbn);
2527c478bd9Sstevel@tonic-gate 			if (!devread(dblk, 0, SUPERBLOCK->fs_bsize,
2537c478bd9Sstevel@tonic-gate 			    (char *)DIRENT)) {
2547c478bd9Sstevel@tonic-gate 				return 0;
2557c478bd9Sstevel@tonic-gate 			}
2567c478bd9Sstevel@tonic-gate 		}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 		dp = (struct direct *)(DIRENT + off);
2597c478bd9Sstevel@tonic-gate 		if (dp->d_ino && substring(name, dp->d_name) == 0)
2607c478bd9Sstevel@tonic-gate 			return (dp->d_ino);
2617c478bd9Sstevel@tonic-gate 		loc += dp->d_reclen;
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate 	return (0);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate #endif /* FSYS_UFS */
267