Home | History | Annotate | Download | only in stage2
      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