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