1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 1999,2000,2001,2002 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 /* Restrictions:
21 This is MINIX V1 only (yet)
22 Disk creation is like:
23 mkfs.minix -c DEVICE
24 */
25
26 #ifdef FSYS_MINIX
27
28 #include "shared.h"
29 #include "filesys.h"
30
31 /* #define DEBUG_MINIX */
32
33 /* indirect blocks */
34 static int mapblock1, mapblock2, namelen;
35
36 /* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
37 #define DEV_BSIZE 512
38
39 /* include/linux/fs.h */
40 #define BLOCK_SIZE_BITS 10
41 #define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
42
43 /* made up, defaults to 1 but can be passed via mount_opts */
44 #define WHICH_SUPER 1
45 /* kind of from fs/ext2/super.c (is OK for minix) */
46 #define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */
47
48 /* include/asm-i386/type.h */
49 typedef __signed__ char __s8;
50 typedef unsigned char __u8;
51 typedef __signed__ short __s16;
52 typedef unsigned short __u16;
53 typedef __signed__ int __s32;
54 typedef unsigned int __u32;
55
56 /* include/linux/minix_fs.h */
57 #define MINIX_ROOT_INO 1
58
59 /* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
60 #define MINIX_LINK_MAX 250
61 #define MINIX2_LINK_MAX 65530
62
63 #define MINIX_I_MAP_SLOTS 8
64 #define MINIX_Z_MAP_SLOTS 64
65 #define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
66 #define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
67 #define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
68 #define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
69 #define MINIX_VALID_FS 0x0001 /* Clean fs. */
70 #define MINIX_ERROR_FS 0x0002 /* fs has errors. */
71
72 #define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
73 #define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
74
75 #define MINIX_V1 0x0001 /* original minix fs */
76 #define MINIX_V2 0x0002 /* minix V2 fs */
77
78 /* originally this is :
79 #define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version
80 here we have */
81 #define INODE_VERSION(inode) (SUPERBLOCK->s_version)
82
83 /*
84 * This is the original minix inode layout on disk.
85 * Note the 8-bit gid and atime and ctime.
86 */
87 struct minix_inode {
88 __u16 i_mode;
89 __u16 i_uid;
90 __u32 i_size;
91 __u32 i_time;
92 __u8 i_gid;
93 __u8 i_nlinks;
94 __u16 i_zone[9];
95 };
96
97 /*
98 * The new minix inode has all the time entries, as well as
99 * long block numbers and a third indirect block (7+1+1+1
100 * instead of 7+1+1). Also, some previously 8-bit values are
101 * now 16-bit. The inode is now 64 bytes instead of 32.
102 */
103 struct minix2_inode {
104 __u16 i_mode;
105 __u16 i_nlinks;
106 __u16 i_uid;
107 __u16 i_gid;
108 __u32 i_size;
109 __u32 i_atime;
110 __u32 i_mtime;
111 __u32 i_ctime;
112 __u32 i_zone[10];
113 };
114
115 /*
116 * minix super-block data on disk
117 */
118 struct minix_super_block {
119 __u16 s_ninodes;
120 __u16 s_nzones;
121 __u16 s_imap_blocks;
122 __u16 s_zmap_blocks;
123 __u16 s_firstdatazone;
124 __u16 s_log_zone_size;
125 __u32 s_max_size;
126 __u16 s_magic;
127 __u16 s_state;
128 __u32 s_zones;
129 };
130
131 struct minix_dir_entry {
132 __u16 inode;
133 char name[0];
134 };
135
136 /* made up, these are pointers into FSYS_BUF */
137 /* read once, always stays there: */
138 #define SUPERBLOCK \
139 ((struct minix_super_block *)(FSYS_BUF))
140 #define INODE \
141 ((struct minix_inode *)((int) SUPERBLOCK + BLOCK_SIZE))
142 #define DATABLOCK1 \
143 ((int)((int)INODE + sizeof(struct minix_inode)))
144 #define DATABLOCK2 \
145 ((int)((int)DATABLOCK1 + BLOCK_SIZE))
146
147 /* linux/stat.h */
148 #define S_IFMT 00170000
149 #define S_IFLNK 0120000
150 #define S_IFREG 0100000
151 #define S_IFDIR 0040000
152 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
153 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
154 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
155
156 #define PATH_MAX 1024 /* include/linux/limits.h */
157 #define MAX_LINK_COUNT 5 /* number of symbolic links to follow */
158
159 /* check filesystem types and read superblock into memory buffer */
160 int
minix_mount(void)161 minix_mount (void)
162 {
163 if (((current_drive & 0x80) || current_slice != 0)
164 && ! IS_PC_SLICE_TYPE_MINIX (current_slice)
165 && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))
166 return 0; /* The partition is not of MINIX type */
167
168 if (part_length < (SBLOCK +
169 (sizeof (struct minix_super_block) / DEV_BSIZE)))
170 return 0; /* The partition is too short */
171
172 if (!devread (SBLOCK, 0, sizeof (struct minix_super_block),
173 (char *) SUPERBLOCK))
174 return 0; /* Cannot read superblock */
175
176 switch (SUPERBLOCK->s_magic)
177 {
178 case MINIX_SUPER_MAGIC:
179 namelen = 14;
180 break;
181 case MINIX_SUPER_MAGIC2:
182 namelen = 30;
183 break;
184 default:
185 return 0; /* Unsupported type */
186 }
187
188 return 1;
189 }
190
191 /* Takes a file system block number and reads it into BUFFER. */
192 static int
minix_rdfsb(int fsblock,int buffer)193 minix_rdfsb (int fsblock, int buffer)
194 {
195 return devread (fsblock * (BLOCK_SIZE / DEV_BSIZE), 0,
196 BLOCK_SIZE, (char *) buffer);
197 }
198
199 /* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
200 a physical block (the location in the file system) via an inode. */
201 static int
minix_block_map(int logical_block)202 minix_block_map (int logical_block)
203 {
204 int i;
205
206 if (logical_block < 7)
207 return INODE->i_zone[logical_block];
208
209 logical_block -= 7;
210 if (logical_block < 512)
211 {
212 i = INODE->i_zone[7];
213
214 if (!i || ((mapblock1 != 1)
215 && !minix_rdfsb (i, DATABLOCK1)))
216 {
217 errnum = ERR_FSYS_CORRUPT;
218 return -1;
219 }
220 mapblock1 = 1;
221 return ((__u16 *) DATABLOCK1) [logical_block];
222 }
223
224 logical_block -= 512;
225 i = INODE->i_zone[8];
226 if (!i || ((mapblock1 != 2)
227 && !minix_rdfsb (i, DATABLOCK1)))
228 {
229 errnum = ERR_FSYS_CORRUPT;
230 return -1;
231 }
232 mapblock1 = 2;
233 i = ((__u16 *) DATABLOCK1)[logical_block >> 9];
234 if (!i || ((mapblock2 != i)
235 && !minix_rdfsb (i, DATABLOCK2)))
236 {
237 errnum = ERR_FSYS_CORRUPT;
238 return -1;
239 }
240 mapblock2 = i;
241 return ((__u16 *) DATABLOCK2)[logical_block & 511];
242 }
243
244 /* read from INODE into BUF */
245 int
minix_read(char * buf,int len)246 minix_read (char *buf, int len)
247 {
248 int logical_block;
249 int offset;
250 int map;
251 int ret = 0;
252 int size = 0;
253
254 while (len > 0)
255 {
256 /* find the (logical) block component of our location */
257 logical_block = filepos >> BLOCK_SIZE_BITS;
258 offset = filepos & (BLOCK_SIZE - 1);
259 map = minix_block_map (logical_block);
260 #ifdef DEBUG_MINIX
261 printf ("map=%d\n", map);
262 #endif
263 if (map < 0)
264 break;
265
266 size = BLOCK_SIZE;
267 size -= offset;
268 if (size > len)
269 size = len;
270
271 disk_read_func = disk_read_hook;
272
273 devread (map * (BLOCK_SIZE / DEV_BSIZE),
274 offset, size, buf);
275
276 disk_read_func = NULL;
277
278 buf += size;
279 len -= size;
280 filepos += size;
281 ret += size;
282 }
283
284 if (errnum)
285 ret = 0;
286
287 return ret;
288 }
289
290 /* preconditions: minix_mount already executed, therefore supblk in buffer
291 known as SUPERBLOCK
292 returns: 0 if error, nonzero iff we were able to find the file successfully
293 postconditions: on a nonzero return, buffer known as INODE contains the
294 inode of the file we were trying to look up
295 side effects: none yet */
296 int
minix_dir(char * dirname)297 minix_dir (char *dirname)
298 {
299 int current_ino = MINIX_ROOT_INO; /* start at the root */
300 int updir_ino = current_ino; /* the parent of the current directory */
301 int ino_blk; /* fs pointer of the inode's info */
302
303 int str_chk = 0; /* used ot hold the results of a string
304 compare */
305
306 struct minix_inode * raw_inode; /* inode info for current_ino */
307
308 char linkbuf[PATH_MAX]; /* buffer for following sym-links */
309 int link_count = 0;
310
311 char * rest;
312 char ch;
313
314 int off; /* offset within block of directory
315 entry */
316 int loc; /* location within a directory */
317 int blk; /* which data blk within dir entry */
318 long map; /* fs pointer of a particular block from
319 dir entry */
320 struct minix_dir_entry * dp; /* pointer to directory entry */
321
322 /* loop invariants:
323 current_ino = inode to lookup
324 dirname = pointer to filename component we are cur looking up within
325 the directory known pointed to by current_ino (if any) */
326
327 #ifdef DEBUG_MINIX
328 printf ("\n");
329 #endif
330
331 while (1)
332 {
333 #ifdef DEBUG_MINIX
334 printf ("inode %d, dirname %s\n", current_ino, dirname);
335 #endif
336
337 ino_blk = (2 + SUPERBLOCK->s_imap_blocks + SUPERBLOCK->s_zmap_blocks
338 + (current_ino - 1) / MINIX_INODES_PER_BLOCK);
339 if (! minix_rdfsb (ino_blk, (int) INODE))
340 return 0;
341
342 /* reset indirect blocks! */
343 mapblock2 = mapblock1 = -1;
344
345 raw_inode = INODE + ((current_ino - 1) % MINIX_INODES_PER_BLOCK);
346
347 /* copy inode to fixed location */
348 memmove ((void *) INODE, (void *) raw_inode,
349 sizeof (struct minix_inode));
350
351 /* If we've got a symbolic link, then chase it. */
352 if (S_ISLNK (INODE->i_mode))
353 {
354 int len;
355
356 if (++link_count > MAX_LINK_COUNT)
357 {
358 errnum = ERR_SYMLINK_LOOP;
359 return 0;
360 }
361 #ifdef DEBUG_MINIX
362 printf ("S_ISLNK (%s)\n", dirname);
363 #endif
364
365 /* Find out how long our remaining name is. */
366 len = 0;
367 while (dirname[len] && !isspace (dirname[len]))
368 len++;
369
370 /* Get the symlink size. */
371 filemax = (INODE->i_size);
372 if (filemax + len > sizeof (linkbuf) - 2)
373 {
374 errnum = ERR_FILELENGTH;
375 return 0;
376 }
377
378 if (len)
379 {
380 /* Copy the remaining name to the end of the symlink data.
381 Note that DIRNAME and LINKBUF may overlap! */
382 memmove (linkbuf + filemax, dirname, len);
383 }
384 linkbuf[filemax + len] = '\0';
385
386 /* Read the necessary blocks, and reset the file pointer. */
387 len = grub_read (linkbuf, filemax);
388 filepos = 0;
389 if (!len)
390 return 0;
391
392 #ifdef DEBUG_MINIX
393 printf ("symlink=%s\n", linkbuf);
394 #endif
395
396 dirname = linkbuf;
397 if (*dirname == '/')
398 {
399 /* It's an absolute link, so look it up in root. */
400 current_ino = MINIX_ROOT_INO;
401 updir_ino = current_ino;
402 }
403 else
404 {
405 /* Relative, so look it up in our parent directory. */
406 current_ino = updir_ino;
407 }
408
409 /* Try again using the new name. */
410 continue;
411 }
412
413 /* If end of filename, INODE points to the file's inode */
414 if (!*dirname || isspace (*dirname))
415 {
416 if (!S_ISREG (INODE->i_mode))
417 {
418 errnum = ERR_BAD_FILETYPE;
419 return 0;
420 }
421
422 filemax = (INODE->i_size);
423 return 1;
424 }
425
426 /* else we have to traverse a directory */
427 updir_ino = current_ino;
428
429 /* skip over slashes */
430 while (*dirname == '/')
431 dirname++;
432
433 /* if this isn't a directory of sufficient size to hold our file,
434 abort */
435 if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode))
436 {
437 errnum = ERR_BAD_FILETYPE;
438 return 0;
439 }
440
441 /* skip to next slash or end of filename (space) */
442 for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
443 rest++);
444
445 /* look through this directory and find the next filename component */
446 /* invariant: rest points to slash after the next filename component */
447 *rest = 0;
448 loc = 0;
449
450 do
451 {
452 #ifdef DEBUG_MINIX
453 printf ("dirname=`%s', rest=`%s', loc=%d\n", dirname, rest, loc);
454 #endif
455
456 /* if our location/byte offset into the directory exceeds the size,
457 give up */
458 if (loc >= INODE->i_size)
459 {
460 if (print_possibilities < 0)
461 {
462 #if 0
463 putchar ('\n');
464 #endif
465 }
466 else
467 {
468 errnum = ERR_FILE_NOT_FOUND;
469 *rest = ch;
470 }
471 return (print_possibilities < 0);
472 }
473
474 /* else, find the (logical) block component of our location */
475 blk = loc >> BLOCK_SIZE_BITS;
476
477 /* we know which logical block of the directory entry we are looking
478 for, now we have to translate that to the physical (fs) block on
479 the disk */
480 map = minix_block_map (blk);
481 #ifdef DEBUG_MINIX
482 printf ("fs block=%d\n", map);
483 #endif
484 mapblock2 = -1;
485 if ((map < 0) || !minix_rdfsb (map, DATABLOCK2))
486 {
487 errnum = ERR_FSYS_CORRUPT;
488 *rest = ch;
489 return 0;
490 }
491 off = loc & (BLOCK_SIZE - 1);
492 dp = (struct minix_dir_entry *) (DATABLOCK2 + off);
493 /* advance loc prematurely to next on-disk directory entry */
494 loc += sizeof (dp->inode) + namelen;
495
496 /* NOTE: minix filenames are NULL terminated if < NAMELEN
497 else exact */
498
499 #ifdef DEBUG_MINIX
500 printf ("directory entry ino=%d\n", dp->inode);
501 if (dp->inode)
502 printf ("entry=%s\n", dp->name);
503 #endif
504
505 if (dp->inode)
506 {
507 int saved_c = dp->name[namelen];
508
509 dp->name[namelen] = 0;
510 str_chk = substring (dirname, dp->name);
511
512 # ifndef STAGE1_5
513 if (print_possibilities && ch != '/'
514 && (!*dirname || str_chk <= 0))
515 {
516 if (print_possibilities > 0)
517 print_possibilities = -print_possibilities;
518 print_a_completion (dp->name);
519 }
520 # endif
521
522 dp->name[namelen] = saved_c;
523 }
524
525 }
526 while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
527
528 current_ino = dp->inode;
529 *(dirname = rest) = ch;
530 }
531 /* never get here */
532 }
533
534 #endif /* FSYS_MINIX */
535