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@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
ufs2_mount(void)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
block_map(int file_block)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
ufs2_read(char * buf,int len)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
ufs2_dir(char * dirname)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
ufs2_embed(unsigned long long * start_sector,int needed_sectors)314 ufs2_embed (unsigned long long *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