1 /* 2 * GRUB -- GRand Unified Bootloader 3 * Copyright (C) 2000, 2001 Free Software Foundation, Inc. 4 * Copyright (c) 2004 Valery Hromov 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21 /* 22 * Elements of this file were originally from the FreeBSD "biosboot" 23 * bootloader file "disk.c" dated 4/12/95. 24 * 25 * The license and header comments from that file are included here. 26 */ 27 28 /* 29 * Mach Operating System 30 * Copyright (c) 1992, 1991 Carnegie Mellon University 31 * All Rights Reserved. 32 * 33 * Permission to use, copy, modify and distribute this software and its 34 * documentation is hereby granted, provided that both the copyright 35 * notice and this permission notice appear in all copies of the 36 * software, derivative works or modified versions, and any portions 37 * thereof, and that both notices appear in supporting documentation. 38 * 39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 42 * 43 * Carnegie Mellon requests users of this software to return to 44 * 45 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 46 * School of Computer Science 47 * Carnegie Mellon University 48 * Pittsburgh PA 15213-3890 49 * 50 * any improvements or extensions that they make and grant Carnegie Mellon 51 * the rights to redistribute these changes. 52 * 53 * from: Mach, Revision 2.2 92/04/04 11:35:49 rpd 54 * $Id: fsys_ufs2.c,v 1.2 2004/06/19 12:17:52 okuji Exp $ 55 */ 56 57 #ifdef FSYS_UFS2 58 59 #include "shared.h" 60 #include "filesys.h" 61 62 #include "ufs2.h" 63 64 /* used for filesystem map blocks */ 65 static int mapblock; 66 static int mapblock_offset; 67 static int mapblock_bsize; 68 69 static int sblock_try[] = SBLOCKSEARCH; 70 static ufs2_daddr_t sblockloc; 71 static int type; 72 73 /* pointer to superblock */ 74 #define SUPERBLOCK ((struct fs *) ( FSYS_BUF + 8192 )) 75 76 #define INODE_UFS2 ((struct ufs2_dinode *) ( FSYS_BUF + 16384 )) 77 78 #define MAPBUF ( FSYS_BUF + 24576 ) 79 #define MAPBUF_LEN 8192 80 81 int 82 ufs2_mount (void) 83 { 84 int retval = 0; 85 int i; 86 87 sblockloc = -1; 88 type = 0; 89 90 if (! (((current_drive & 0x80) || (current_slice != 0)) 91 && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_BSDFFS))) 92 { 93 for (i = 0; sblock_try[i] != -1; ++i) 94 { 95 if (! (part_length < (sblock_try[i] + (SBLOCKSIZE / DEV_BSIZE)) 96 || ! devread (0, sblock_try[i], SBLOCKSIZE, (char *) SUPERBLOCK))) 97 { 98 if (SUPERBLOCK->fs_magic == FS_UFS2_MAGIC /* && 99 (SUPERBLOCK->fs_sblockloc == sblockloc || 100 (SUPERBLOCK->fs_old_flags & FS_FLAGS_UPDATED) == 0)*/) 101 { 102 type = 2; 103 } 104 else 105 { 106 continue; 107 } 108 109 retval = 1; 110 sblockloc = sblock_try[i]; 111 break; 112 } 113 } 114 } 115 116 mapblock = -1; 117 mapblock_offset = -1; 118 119 return retval; 120 } 121 122 static grub_int64_t 123 block_map (int file_block) 124 { 125 int bnum, offset, bsize; 126 127 if (file_block < NDADDR) 128 return (INODE_UFS2->di_db[file_block]); 129 130 /* If the blockmap loaded does not include FILE_BLOCK, 131 load a new blockmap. */ 132 133 if ((bnum = fsbtodb (SUPERBLOCK, INODE_UFS2->di_ib[0])) != mapblock 134 || (mapblock_offset <= bnum && bnum <= mapblock_offset + mapblock_bsize)) 135 { 136 if (MAPBUF_LEN < SUPERBLOCK->fs_bsize) 137 { 138 offset = ((file_block - NDADDR) % NINDIR (SUPERBLOCK)); 139 bsize = MAPBUF_LEN; 140 141 if (offset + MAPBUF_LEN > SUPERBLOCK->fs_bsize) 142 offset = (SUPERBLOCK->fs_bsize - MAPBUF_LEN) / sizeof (int); 143 } 144 else 145 { 146 bsize = SUPERBLOCK->fs_bsize; 147 offset = 0; 148 } 149 150 if (! devread (bnum, offset * sizeof (int), bsize, (char *) MAPBUF)) 151 { 152 mapblock = -1; 153 mapblock_bsize = -1; 154 mapblock_offset = -1; 155 errnum = ERR_FSYS_CORRUPT; 156 return -1; 157 } 158 159 mapblock = bnum; 160 mapblock_bsize = bsize; 161 mapblock_offset = offset; 162 } 163 164 return (((grub_int64_t *) MAPBUF)[((file_block - NDADDR) % NINDIR (SUPERBLOCK)) 165 - mapblock_offset]); 166 } 167 168 int 169 ufs2_read (char *buf, int len) 170 { 171 int logno, off, size, ret = 0; 172 grub_int64_t map; 173 174 while (len && !errnum) 175 { 176 off = blkoff (SUPERBLOCK, filepos); 177 logno = lblkno (SUPERBLOCK, filepos); 178 size = blksize (SUPERBLOCK, INODE_UFS2, logno); 179 180 if ((map = block_map (logno)) < 0) 181 break; 182 183 size -= off; 184 185 if (size > len) 186 size = len; 187 188 disk_read_func = disk_read_hook; 189 190 devread (fsbtodb (SUPERBLOCK, map), off, size, buf); 191 192 disk_read_func = NULL; 193 194 buf += size; 195 len -= size; 196 filepos += size; 197 ret += size; 198 } 199 200 if (errnum) 201 ret = 0; 202 203 return ret; 204 } 205 206 int 207 ufs2_dir (char *dirname) 208 { 209 char *rest, ch; 210 int block, off, loc, ino = ROOTINO; 211 grub_int64_t map; 212 struct direct *dp; 213 214 /* main loop to find destination inode */ 215 loop: 216 217 /* load current inode (defaults to the root inode) */ 218 219 if (!devread (fsbtodb (SUPERBLOCK, ino_to_fsba (SUPERBLOCK, ino)), 220 ino % (SUPERBLOCK->fs_inopb) * sizeof (struct ufs2_dinode), 221 sizeof (struct ufs2_dinode), (char *) INODE_UFS2)) 222 return 0; /* XXX what return value? */ 223 224 /* if we have a real file (and we're not just printing possibilities), 225 then this is where we want to exit */ 226 227 if (!*dirname || isspace (*dirname)) 228 { 229 if ((INODE_UFS2->di_mode & IFMT) != IFREG) 230 { 231 errnum = ERR_BAD_FILETYPE; 232 return 0; 233 } 234 235 filemax = INODE_UFS2->di_size; 236 237 /* incomplete implementation requires this! */ 238 fsmax = (NDADDR + NINDIR (SUPERBLOCK)) * SUPERBLOCK->fs_bsize; 239 return 1; 240 } 241 242 /* continue with file/directory name interpretation */ 243 244 while (*dirname == '/') 245 dirname++; 246 247 if (!(INODE_UFS2->di_size) || ((INODE_UFS2->di_mode & IFMT) != IFDIR)) 248 { 249 errnum = ERR_BAD_FILETYPE; 250 return 0; 251 } 252 253 for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++); 254 255 *rest = 0; 256 loc = 0; 257 258 /* loop for reading a the entries in a directory */ 259 260 do 261 { 262 if (loc >= INODE_UFS2->di_size) 263 { 264 if (print_possibilities < 0) 265 return 1; 266 267 errnum = ERR_FILE_NOT_FOUND; 268 *rest = ch; 269 return 0; 270 } 271 272 if (!(off = blkoff (SUPERBLOCK, loc))) 273 { 274 block = lblkno (SUPERBLOCK, loc); 275 276 if ((map = block_map (block)) < 0 277 || !devread (fsbtodb (SUPERBLOCK, map), 0, 278 blksize (SUPERBLOCK, INODE_UFS2, block), 279 (char *) FSYS_BUF)) 280 { 281 errnum = ERR_FSYS_CORRUPT; 282 *rest = ch; 283 return 0; 284 } 285 } 286 287 dp = (struct direct *) (FSYS_BUF + off); 288 loc += dp->d_reclen; 289 290 #ifndef STAGE1_5 291 if (dp->d_ino && print_possibilities && ch != '/' 292 && (!*dirname || substring (dirname, dp->d_name) <= 0)) 293 { 294 if (print_possibilities > 0) 295 print_possibilities = -print_possibilities; 296 297 print_a_completion (dp->d_name); 298 } 299 #endif /* STAGE1_5 */ 300 } 301 while (!dp->d_ino || (substring (dirname, dp->d_name) != 0 302 || (print_possibilities && ch != '/'))); 303 304 /* only get here if we have a matching directory entry */ 305 306 ino = dp->d_ino; 307 *(dirname = rest) = ch; 308 309 /* go back to main loop at top of function */ 310 goto loop; 311 } 312 313 int 314 ufs2_embed (int *start_sector, int needed_sectors) 315 { 316 /* XXX: I don't know if this is really correct. Someone who is 317 familiar with BSD should check for this. */ 318 if (needed_sectors > 14) 319 return 0; 320 321 *start_sector = 1; 322 #if 1 323 /* FIXME: Disable the embedding in FFS until someone checks if 324 the code above is correct. */ 325 return 0; 326 #else 327 return 1; 328 #endif 329 } 330 331 #endif /* FSYS_UFS2 */ 332