1 /* 2 * GRUB -- GRand Unified Bootloader 3 * Copyright (C) 2006 Free Software Foundation, Inc. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 /* 20 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 21 * Use is subject to license terms. 22 */ 23 24 /* From Solaris usr/src/stand/lib/fs/ufs/ufsops.c */ 25 26 #ifdef FSYS_UFS 27 28 #include "shared.h" 29 #include "filesys.h" 30 31 #include "ufs.h" 32 33 /* These are the pools of buffers, etc. */ 34 35 #define SUPERBLOCK ((struct fs *)(FSYS_BUF + 0x2000)) 36 #define INODE ((struct icommon *)(FSYS_BUF + 0x1000)) 37 #define DIRENT (FSYS_BUF + 0x4000) 38 #define INDIRBLK1 ((grub_daddr32_t *)(FSYS_BUF + 0x4000)) /* 2+ indir blk */ 39 #define INDIRBLK0 ((grub_daddr32_t *)(FSYS_BUF+ 0x6000)) /* 1st indirect blk */ 40 41 static int indirblk0, indirblk1; 42 43 static int openi(grub_ino_t); 44 static grub_ino_t dlook(grub_ino_t, char *); 45 static grub_daddr32_t sbmap(grub_daddr32_t); 46 47 /* read superblock and check fs magic */ 48 int 49 ufs_mount(void) 50 { 51 if (! IS_PC_SLICE_TYPE_SOLARIS(current_slice) || 52 !devread(UFS_SBLOCK, 0, UFS_SBSIZE, (char *)SUPERBLOCK) || 53 SUPERBLOCK->fs_magic != UFS_MAGIC) 54 return 0; 55 56 return 1; 57 } 58 59 60 /* 61 * searching for a file, if successful, inode will be loaded in INODE 62 * The entry point should really be named ufs_open(char *pathname). 63 * For now, keep it consistent with the rest of fsys modules. 64 */ 65 int 66 ufs_dir(char *dirname) 67 { 68 grub_ino_t inode = ROOTINO; /* start from root */ 69 char *fname, ch; 70 71 indirblk0 = indirblk1 = 0; 72 73 /* skip leading slashes */ 74 while (*dirname == '/') 75 dirname++; 76 77 while (inode && *dirname && !isspace(*dirname)) { 78 if (!openi(inode)) 79 return 0; 80 81 /* parse for next path component */ 82 fname = dirname; 83 while (*dirname && !isspace(*dirname) && *dirname != '/') 84 dirname++; 85 ch = *dirname; 86 *dirname = 0; /* ensure null termination */ 87 88 inode = dlook(inode, fname); 89 *dirname = ch; 90 while (*dirname == '/') 91 dirname++; 92 } 93 94 /* return 1 only if inode exists and is a regular file */ 95 if (! openi(inode)) 96 return (0); 97 filepos = 0; 98 filemax = INODE->ic_sizelo; 99 return (inode && ((INODE->ic_smode & IFMT) == IFREG)); 100 } 101 102 /* 103 * This is the high-level read function. 104 */ 105 int 106 ufs_read(char *buf, int len) 107 { 108 int off, size, ret = 0, ok; 109 grub_daddr32_t lblk, dblk; 110 111 while (len) { 112 off = blkoff(SUPERBLOCK, filepos); 113 lblk = lblkno(SUPERBLOCK, filepos); 114 size = SUPERBLOCK->fs_bsize; 115 size -= off; 116 if (size > len) 117 size = len; 118 119 if ((dblk = sbmap(lblk)) <= 0) { 120 /* we are in a file hole, just zero the buf */ 121 grub_memset(buf, 0, size); 122 } else { 123 disk_read_func = disk_read_hook; 124 ok = devread(fsbtodb(SUPERBLOCK, dblk), off, size, buf); 125 disk_read_func = 0; 126 if (!ok) 127 return 0; 128 } 129 buf += size; 130 len -= size; 131 filepos += size; 132 ret += size; 133 } 134 135 return (ret); 136 } 137 138 int 139 ufs_embed (int *start_sector, int needed_sectors) 140 { 141 if (needed_sectors > 14) 142 return 0; 143 144 *start_sector = 2; 145 return 1; 146 } 147 148 /* read inode and place content in INODE */ 149 static int 150 openi(grub_ino_t inode) 151 { 152 grub_daddr32_t dblk; 153 int off; 154 155 /* get block and byte offset into the block */ 156 dblk = fsbtodb(SUPERBLOCK, itod(SUPERBLOCK, inode)); 157 off = itoo(SUPERBLOCK, inode) * sizeof (struct icommon); 158 159 return (devread(dblk, off, sizeof (struct icommon), (char *)INODE)); 160 } 161 162 /* 163 * Performs fileblock mapping. Convert file block no. to disk block no. 164 * Returns 0 when block doesn't exist and <0 when block isn't initialized 165 * (i.e belongs to a hole in the file). 166 */ 167 grub_daddr32_t 168 sbmap(grub_daddr32_t bn) 169 { 170 int level, bound, i, index; 171 grub_daddr32_t nb, blkno; 172 grub_daddr32_t *db = INODE->ic_db; 173 174 /* blocks 0..UFS_NDADDR are direct blocks */ 175 if (bn < UFS_NDADDR) { 176 return db[bn]; 177 } 178 179 /* determine how many levels of indirection. */ 180 level = 0; 181 bn -= UFS_NDADDR; 182 bound = UFS_NINDIR(SUPERBLOCK); 183 while (bn >= bound) { 184 level++; 185 bn -= bound; 186 bound *= UFS_NINDIR(SUPERBLOCK); 187 } 188 if (level >= UFS_NIADDR) /* bn too big */ 189 return ((grub_daddr32_t)0); 190 191 /* fetch the first indirect block */ 192 nb = INODE->ic_ib[level]; 193 if (nb == 0) { 194 return ((grub_daddr32_t)0); 195 } 196 if (indirblk0 != nb) { 197 indirblk0 = 0; 198 blkno = fsbtodb(SUPERBLOCK, nb); 199 if (!devread(blkno, 0, SUPERBLOCK->fs_bsize, 200 (char *)INDIRBLK0)) 201 return (0); 202 indirblk0 = nb; 203 } 204 bound /= UFS_NINDIR(SUPERBLOCK); 205 index = (bn / bound) % UFS_NINDIR(SUPERBLOCK); 206 nb = INDIRBLK0[index]; 207 208 /* fetch through the indirect blocks */ 209 for (i = 1; i <= level; i++) { 210 if (indirblk1 != nb) { 211 blkno = fsbtodb(SUPERBLOCK, nb); 212 if (!devread(blkno, 0, SUPERBLOCK->fs_bsize, 213 (char *)INDIRBLK1)) 214 return (0); 215 indirblk1 = nb; 216 } 217 bound /= UFS_NINDIR(SUPERBLOCK); 218 index = (bn / bound) % UFS_NINDIR(SUPERBLOCK); 219 nb = INDIRBLK1[index]; 220 if (nb == 0) 221 return ((grub_daddr32_t)0); 222 } 223 224 return (nb); 225 } 226 227 /* search directory content for name, return inode number */ 228 static grub_ino_t 229 dlook(grub_ino_t dir_ino, char *name) 230 { 231 int loc, off; 232 grub_daddr32_t lbn, dbn, dblk; 233 struct direct *dp; 234 235 if ((INODE->ic_smode & IFMT) != IFDIR) 236 return 0; 237 238 loc = 0; 239 while (loc < INODE->ic_sizelo) { 240 /* offset into block */ 241 off = blkoff(SUPERBLOCK, loc); 242 if (off == 0) { /* need to read in a new block */ 243 244 /* get logical block number */ 245 lbn = lblkno(SUPERBLOCK, loc); 246 /* resolve indrect blocks */ 247 dbn = sbmap(lbn); 248 if (dbn == 0) 249 return (0); 250 251 dblk = fsbtodb(SUPERBLOCK, dbn); 252 if (!devread(dblk, 0, SUPERBLOCK->fs_bsize, 253 (char *)DIRENT)) { 254 return 0; 255 } 256 } 257 258 dp = (struct direct *)(DIRENT + off); 259 if (dp->d_ino && substring(name, dp->d_name) == 0) 260 return (dp->d_ino); 261 loc += dp->d_reclen; 262 } 263 return (0); 264 } 265 266 #endif /* FSYS_UFS */ 267