xref: /illumos-gate/usr/src/grub/grub-0.97/stage2/fsys_ufs.c (revision 2e1aefd1b4539a3d6cf03dbfa515eabf4de09f59)
11b8adde7SWilliam Kucharski /*
21b8adde7SWilliam Kucharski  *  GRUB  --  GRand Unified Bootloader
31b8adde7SWilliam Kucharski  *  Copyright (C) 2006 Free Software Foundation, Inc.
41b8adde7SWilliam Kucharski  *
51b8adde7SWilliam Kucharski  *  This program is free software; you can redistribute it and/or modify
61b8adde7SWilliam Kucharski  *  it under the terms of the GNU General Public License as published by
71b8adde7SWilliam Kucharski  *  the Free Software Foundation; either version 2 of the License, or
81b8adde7SWilliam Kucharski  *  (at your option) any later version.
91b8adde7SWilliam Kucharski  *
101b8adde7SWilliam Kucharski  *  This program is distributed in the hope that it will be useful,
111b8adde7SWilliam Kucharski  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
121b8adde7SWilliam Kucharski  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
131b8adde7SWilliam Kucharski  *  GNU General Public License for more details.
141b8adde7SWilliam Kucharski  *
151b8adde7SWilliam Kucharski  *  You should have received a copy of the GNU General Public License
161b8adde7SWilliam Kucharski  *  along with this program; if not, write to the Free Software
171b8adde7SWilliam Kucharski  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
181b8adde7SWilliam Kucharski  */
191b8adde7SWilliam Kucharski /*
201b8adde7SWilliam Kucharski  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
211b8adde7SWilliam Kucharski  * Use is subject to license terms.
221b8adde7SWilliam Kucharski  */
231b8adde7SWilliam Kucharski 
241b8adde7SWilliam Kucharski /* From Solaris usr/src/stand/lib/fs/ufs/ufsops.c */
251b8adde7SWilliam Kucharski 
261b8adde7SWilliam Kucharski #ifdef	FSYS_UFS
271b8adde7SWilliam Kucharski 
281b8adde7SWilliam Kucharski #include "shared.h"
291b8adde7SWilliam Kucharski #include "filesys.h"
301b8adde7SWilliam Kucharski 
311b8adde7SWilliam Kucharski #include "ufs.h"
321b8adde7SWilliam Kucharski 
331b8adde7SWilliam Kucharski /* These are the pools of buffers, etc. */
341b8adde7SWilliam Kucharski 
351b8adde7SWilliam Kucharski #define SUPERBLOCK ((struct fs *)(FSYS_BUF + 0x2000))
361b8adde7SWilliam Kucharski #define	INODE ((struct icommon *)(FSYS_BUF + 0x1000))
371b8adde7SWilliam Kucharski #define DIRENT (FSYS_BUF + 0x4000)
381b8adde7SWilliam Kucharski #define INDIRBLK1 ((grub_daddr32_t *)(FSYS_BUF + 0x4000)) /* 2+ indir blk */
391b8adde7SWilliam Kucharski #define	INDIRBLK0 ((grub_daddr32_t *)(FSYS_BUF+ 0x6000))  /* 1st indirect blk */
401b8adde7SWilliam Kucharski 
411b8adde7SWilliam Kucharski static int indirblk0, indirblk1;
421b8adde7SWilliam Kucharski 
431b8adde7SWilliam Kucharski static int openi(grub_ino_t);
441b8adde7SWilliam Kucharski static grub_ino_t dlook(grub_ino_t, char *);
451b8adde7SWilliam Kucharski static grub_daddr32_t sbmap(grub_daddr32_t);
461b8adde7SWilliam Kucharski 
471b8adde7SWilliam Kucharski /* read superblock and check fs magic */
481b8adde7SWilliam Kucharski int
ufs_mount(void)491b8adde7SWilliam Kucharski ufs_mount(void)
501b8adde7SWilliam Kucharski {
511b8adde7SWilliam Kucharski 	if (! IS_PC_SLICE_TYPE_SOLARIS(current_slice) ||
521b8adde7SWilliam Kucharski 	    !devread(UFS_SBLOCK, 0, UFS_SBSIZE, (char *)SUPERBLOCK) ||
531b8adde7SWilliam Kucharski 	    SUPERBLOCK->fs_magic != UFS_MAGIC)
541b8adde7SWilliam Kucharski 		return 0;
551b8adde7SWilliam Kucharski 
561b8adde7SWilliam Kucharski 	return 1;
571b8adde7SWilliam Kucharski }
581b8adde7SWilliam Kucharski 
591b8adde7SWilliam Kucharski 
601b8adde7SWilliam Kucharski /*
611b8adde7SWilliam Kucharski  * searching for a file, if successful, inode will be loaded in INODE
621b8adde7SWilliam Kucharski  * The entry point should really be named ufs_open(char *pathname).
631b8adde7SWilliam Kucharski  * For now, keep it consistent with the rest of fsys modules.
641b8adde7SWilliam Kucharski  */
651b8adde7SWilliam Kucharski int
ufs_dir(char * dirname)661b8adde7SWilliam Kucharski ufs_dir(char *dirname)
671b8adde7SWilliam Kucharski {
681b8adde7SWilliam Kucharski 	grub_ino_t inode = ROOTINO;	/* start from root */
691b8adde7SWilliam Kucharski 	char *fname, ch;
701b8adde7SWilliam Kucharski 
711b8adde7SWilliam Kucharski 	indirblk0 = indirblk1 = 0;
721b8adde7SWilliam Kucharski 
731b8adde7SWilliam Kucharski 	/* skip leading slashes */
741b8adde7SWilliam Kucharski 	while (*dirname == '/')
751b8adde7SWilliam Kucharski 		dirname++;
761b8adde7SWilliam Kucharski 
771b8adde7SWilliam Kucharski 	while (inode && *dirname && !isspace(*dirname)) {
781b8adde7SWilliam Kucharski 		if (!openi(inode))
791b8adde7SWilliam Kucharski 			return 0;
801b8adde7SWilliam Kucharski 
811b8adde7SWilliam Kucharski 		/* parse for next path component */
821b8adde7SWilliam Kucharski 		fname = dirname;
831b8adde7SWilliam Kucharski 		while (*dirname && !isspace(*dirname) && *dirname != '/')
841b8adde7SWilliam Kucharski 			dirname++;
851b8adde7SWilliam Kucharski 		ch = *dirname;
861b8adde7SWilliam Kucharski 		*dirname = 0;	/* ensure null termination */
871b8adde7SWilliam Kucharski 
881b8adde7SWilliam Kucharski 		inode = dlook(inode, fname);
891b8adde7SWilliam Kucharski 		*dirname = ch;
901b8adde7SWilliam Kucharski 		while (*dirname == '/')
911b8adde7SWilliam Kucharski 			dirname++;
921b8adde7SWilliam Kucharski 	}
931b8adde7SWilliam Kucharski 
941b8adde7SWilliam Kucharski 	/* return 1 only if inode exists and is a regular file */
951b8adde7SWilliam Kucharski 	if  (! openi(inode))
961b8adde7SWilliam Kucharski 		return (0);
971b8adde7SWilliam Kucharski 	filepos = 0;
981b8adde7SWilliam Kucharski 	filemax = INODE->ic_sizelo;
991b8adde7SWilliam Kucharski 	return (inode && ((INODE->ic_smode & IFMT) == IFREG));
1001b8adde7SWilliam Kucharski }
1011b8adde7SWilliam Kucharski 
1021b8adde7SWilliam Kucharski /*
1031b8adde7SWilliam Kucharski  * This is the high-level read function.
1041b8adde7SWilliam Kucharski  */
1051b8adde7SWilliam Kucharski int
ufs_read(char * buf,int len)1061b8adde7SWilliam Kucharski ufs_read(char *buf, int len)
1071b8adde7SWilliam Kucharski {
1081b8adde7SWilliam Kucharski   	int off, size, ret = 0, ok;
1091b8adde7SWilliam Kucharski 	grub_daddr32_t lblk, dblk;
1101b8adde7SWilliam Kucharski 
1111b8adde7SWilliam Kucharski   	while (len) {
1121b8adde7SWilliam Kucharski 	  	off = blkoff(SUPERBLOCK, filepos);
1131b8adde7SWilliam Kucharski 		lblk = lblkno(SUPERBLOCK, filepos);
1141b8adde7SWilliam Kucharski 		size = SUPERBLOCK->fs_bsize;
1151b8adde7SWilliam Kucharski 		size -= off;
1161b8adde7SWilliam Kucharski 		if (size > len)
1171b8adde7SWilliam Kucharski 		  	size = len;
1181b8adde7SWilliam Kucharski 
1191b8adde7SWilliam Kucharski 		if ((dblk = sbmap(lblk)) <= 0) {
1201b8adde7SWilliam Kucharski 			/* we are in a file hole, just zero the buf */
1211b8adde7SWilliam Kucharski 			grub_memset(buf, 0, size);
1221b8adde7SWilliam Kucharski 		} else {
1231b8adde7SWilliam Kucharski 			disk_read_func = disk_read_hook;
1241b8adde7SWilliam Kucharski 			ok = devread(fsbtodb(SUPERBLOCK, dblk), off, size, buf);
1251b8adde7SWilliam Kucharski 			disk_read_func = 0;
1261b8adde7SWilliam Kucharski 			if (!ok)
1271b8adde7SWilliam Kucharski 		  		return 0;
1281b8adde7SWilliam Kucharski 		}
1291b8adde7SWilliam Kucharski 		buf += size;
1301b8adde7SWilliam Kucharski 		len -= size;
1311b8adde7SWilliam Kucharski 		filepos += size;
1321b8adde7SWilliam Kucharski 		ret += size;
1331b8adde7SWilliam Kucharski 	}
1341b8adde7SWilliam Kucharski 
1351b8adde7SWilliam Kucharski 	return (ret);
1361b8adde7SWilliam Kucharski }
1371b8adde7SWilliam Kucharski 
1381b8adde7SWilliam Kucharski 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)
1401b8adde7SWilliam Kucharski {
1411b8adde7SWilliam Kucharski 	if (needed_sectors > 14)
1421b8adde7SWilliam Kucharski         	return 0;
1431b8adde7SWilliam Kucharski 
1441b8adde7SWilliam Kucharski 	*start_sector = 2;
1451b8adde7SWilliam Kucharski 	return 1;
1461b8adde7SWilliam Kucharski }
1471b8adde7SWilliam Kucharski 
1481b8adde7SWilliam Kucharski /* read inode and place content in INODE */
1491b8adde7SWilliam Kucharski static int
openi(grub_ino_t inode)1501b8adde7SWilliam Kucharski openi(grub_ino_t inode)
1511b8adde7SWilliam Kucharski {
1521b8adde7SWilliam Kucharski 	grub_daddr32_t dblk;
1531b8adde7SWilliam Kucharski 	int off;
1541b8adde7SWilliam Kucharski 
1551b8adde7SWilliam Kucharski 	/* get block and byte offset into the block */
1561b8adde7SWilliam Kucharski 	dblk = fsbtodb(SUPERBLOCK, itod(SUPERBLOCK, inode));
1571b8adde7SWilliam Kucharski 	off = itoo(SUPERBLOCK, inode) * sizeof (struct icommon);
1581b8adde7SWilliam Kucharski 
1591b8adde7SWilliam Kucharski 	return (devread(dblk, off, sizeof (struct icommon), (char *)INODE));
1601b8adde7SWilliam Kucharski }
1611b8adde7SWilliam Kucharski 
1621b8adde7SWilliam Kucharski /*
1631b8adde7SWilliam Kucharski  * Performs fileblock mapping. Convert file block no. to disk block no.
1641b8adde7SWilliam Kucharski  * Returns 0 when block doesn't exist and <0 when block isn't initialized
1651b8adde7SWilliam Kucharski  * (i.e belongs to a hole in the file).
1661b8adde7SWilliam Kucharski  */
1671b8adde7SWilliam Kucharski grub_daddr32_t
sbmap(grub_daddr32_t bn)1681b8adde7SWilliam Kucharski sbmap(grub_daddr32_t bn)
1691b8adde7SWilliam Kucharski {
1701b8adde7SWilliam Kucharski   	int level, bound, i, index;
1711b8adde7SWilliam Kucharski 	grub_daddr32_t nb, blkno;
1721b8adde7SWilliam Kucharski 	grub_daddr32_t *db = INODE->ic_db;
1731b8adde7SWilliam Kucharski 
1741b8adde7SWilliam Kucharski 	/* blocks 0..UFS_NDADDR are direct blocks */
1751b8adde7SWilliam Kucharski 	if (bn < UFS_NDADDR) {
1761b8adde7SWilliam Kucharski 		return db[bn];
1771b8adde7SWilliam Kucharski 	}
1781b8adde7SWilliam Kucharski 
1791b8adde7SWilliam Kucharski 	/* determine how many levels of indirection. */
1801b8adde7SWilliam Kucharski 	level = 0;
1811b8adde7SWilliam Kucharski 	bn -= UFS_NDADDR;
1821b8adde7SWilliam Kucharski 	bound = UFS_NINDIR(SUPERBLOCK);
1831b8adde7SWilliam Kucharski 	while (bn >= bound) {
1841b8adde7SWilliam Kucharski 		level++;
1851b8adde7SWilliam Kucharski 		bn -= bound;
1861b8adde7SWilliam Kucharski 		bound *= UFS_NINDIR(SUPERBLOCK);
1871b8adde7SWilliam Kucharski 	}
1881b8adde7SWilliam Kucharski 	if (level >= UFS_NIADDR)	/* bn too big */
1891b8adde7SWilliam Kucharski 		return ((grub_daddr32_t)0);
1901b8adde7SWilliam Kucharski 
1911b8adde7SWilliam Kucharski 	/* fetch the first indirect block */
1921b8adde7SWilliam Kucharski 	nb = INODE->ic_ib[level];
1931b8adde7SWilliam Kucharski 	if (nb == 0) {
1941b8adde7SWilliam Kucharski 		return ((grub_daddr32_t)0);
1951b8adde7SWilliam Kucharski 	}
1961b8adde7SWilliam Kucharski 	if (indirblk0 != nb) {
1971b8adde7SWilliam Kucharski 		indirblk0 = 0;
1981b8adde7SWilliam Kucharski 		blkno = fsbtodb(SUPERBLOCK, nb);
1991b8adde7SWilliam Kucharski 		if (!devread(blkno, 0, SUPERBLOCK->fs_bsize,
2001b8adde7SWilliam Kucharski 		    (char *)INDIRBLK0))
2011b8adde7SWilliam Kucharski 			return (0);
2021b8adde7SWilliam Kucharski 		indirblk0 = nb;
2031b8adde7SWilliam Kucharski 	}
2041b8adde7SWilliam Kucharski 	bound /= UFS_NINDIR(SUPERBLOCK);
2051b8adde7SWilliam Kucharski 	index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
2061b8adde7SWilliam Kucharski 	nb = INDIRBLK0[index];
2071b8adde7SWilliam Kucharski 
2081b8adde7SWilliam Kucharski 	/* fetch through the indirect blocks */
2091b8adde7SWilliam Kucharski 	for (i = 1; i <= level; i++) {
2101b8adde7SWilliam Kucharski 		if (indirblk1 != nb) {
2111b8adde7SWilliam Kucharski 			blkno = fsbtodb(SUPERBLOCK, nb);
2121b8adde7SWilliam Kucharski 			if (!devread(blkno, 0, SUPERBLOCK->fs_bsize,
2131b8adde7SWilliam Kucharski 			    (char *)INDIRBLK1))
2141b8adde7SWilliam Kucharski 				return (0);
2151b8adde7SWilliam Kucharski 			indirblk1 = nb;
2161b8adde7SWilliam Kucharski 		}
2171b8adde7SWilliam Kucharski 		bound /= UFS_NINDIR(SUPERBLOCK);
2181b8adde7SWilliam Kucharski 		index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
2191b8adde7SWilliam Kucharski 		nb = INDIRBLK1[index];
2201b8adde7SWilliam Kucharski 		if (nb == 0)
2211b8adde7SWilliam Kucharski 			return ((grub_daddr32_t)0);
2221b8adde7SWilliam Kucharski 	}
2231b8adde7SWilliam Kucharski 
2241b8adde7SWilliam Kucharski 	return (nb);
2251b8adde7SWilliam Kucharski }
2261b8adde7SWilliam Kucharski 
2271b8adde7SWilliam Kucharski /* search directory content for name, return inode number */
2281b8adde7SWilliam Kucharski static grub_ino_t
dlook(grub_ino_t dir_ino,char * name)2291b8adde7SWilliam Kucharski dlook(grub_ino_t dir_ino, char *name)
2301b8adde7SWilliam Kucharski {
2311b8adde7SWilliam Kucharski 	int loc, off;
2321b8adde7SWilliam Kucharski 	grub_daddr32_t lbn, dbn, dblk;
2331b8adde7SWilliam Kucharski 	struct direct *dp;
2341b8adde7SWilliam Kucharski 
2351b8adde7SWilliam Kucharski 	if ((INODE->ic_smode & IFMT) != IFDIR)
2361b8adde7SWilliam Kucharski 		return 0;
2371b8adde7SWilliam Kucharski 
2381b8adde7SWilliam Kucharski 	loc = 0;
2391b8adde7SWilliam Kucharski 	while (loc < INODE->ic_sizelo) {
2401b8adde7SWilliam Kucharski 	  	/* offset into block */
2411b8adde7SWilliam Kucharski 		off = blkoff(SUPERBLOCK, loc);
2421b8adde7SWilliam Kucharski 		if (off == 0) {		/* need to read in a new block */
2431b8adde7SWilliam Kucharski 
2441b8adde7SWilliam Kucharski 		  	/* get logical block number */
2451b8adde7SWilliam Kucharski 			lbn = lblkno(SUPERBLOCK, loc);
2461b8adde7SWilliam Kucharski 			/* resolve indrect blocks */
2471b8adde7SWilliam Kucharski 			dbn = sbmap(lbn);
2481b8adde7SWilliam Kucharski 			if (dbn == 0)
2491b8adde7SWilliam Kucharski 				return (0);
2501b8adde7SWilliam Kucharski 
2511b8adde7SWilliam Kucharski 			dblk = fsbtodb(SUPERBLOCK, dbn);
2521b8adde7SWilliam Kucharski 			if (!devread(dblk, 0, SUPERBLOCK->fs_bsize,
2531b8adde7SWilliam Kucharski 			    (char *)DIRENT)) {
2541b8adde7SWilliam Kucharski 				return 0;
2551b8adde7SWilliam Kucharski 			}
2561b8adde7SWilliam Kucharski 		}
2571b8adde7SWilliam Kucharski 
2581b8adde7SWilliam Kucharski 		dp = (struct direct *)(DIRENT + off);
2591b8adde7SWilliam Kucharski 		if (dp->d_ino && substring(name, dp->d_name) == 0)
2601b8adde7SWilliam Kucharski 			return (dp->d_ino);
2611b8adde7SWilliam Kucharski 		loc += dp->d_reclen;
2621b8adde7SWilliam Kucharski 	}
2631b8adde7SWilliam Kucharski 	return (0);
2641b8adde7SWilliam Kucharski }
2651b8adde7SWilliam Kucharski 
2661b8adde7SWilliam Kucharski #endif /* FSYS_UFS */
267