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