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