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