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 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 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 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 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 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