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(int * start_sector,int needed_sectors)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