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@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.1.1.1 2003/11/20 02:04:59 fengshuo 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
ffs_mount(void)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
block_map(int file_block)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
ffs_read(char * buf,int len)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
ffs_dir(char * dirname)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
ffs_embed(unsigned long long * start_sector,int needed_sectors)293 ffs_embed (unsigned long long *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