X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=qemu%2Froms%2Fopenbios%2Ffs%2Fgrubfs%2Ffsys_minix.c;fp=qemu%2Froms%2Fopenbios%2Ffs%2Fgrubfs%2Ffsys_minix.c;h=d16b58c871002764e0c2233182d019e739a06dd7;hb=e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb;hp=0000000000000000000000000000000000000000;hpb=9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00;p=kvmfornfv.git diff --git a/qemu/roms/openbios/fs/grubfs/fsys_minix.c b/qemu/roms/openbios/fs/grubfs/fsys_minix.c new file mode 100644 index 000000000..d16b58c87 --- /dev/null +++ b/qemu/roms/openbios/fs/grubfs/fsys_minix.c @@ -0,0 +1,535 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/* Restrictions: + This is MINIX V1 only (yet) + Disk creation is like: + mkfs.minix -c DEVICE +*/ + +#ifdef FSYS_MINIX + +#include "shared.h" +#include "filesys.h" + +/* #define DEBUG_MINIX */ + +/* indirect blocks */ +static int mapblock1, mapblock2, namelen; + +/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */ +#define DEV_BSIZE 512 + +/* include/linux/fs.h */ +#define BLOCK_SIZE_BITS 10 +#define BLOCK_SIZE (1<. Oh well. */ +#define MINIX_LINK_MAX 250 +#define MINIX2_LINK_MAX 65530 + +#define MINIX_I_MAP_SLOTS 8 +#define MINIX_Z_MAP_SLOTS 64 +#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ +#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ +#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */ +#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ +#define MINIX_VALID_FS 0x0001 /* Clean fs. */ +#define MINIX_ERROR_FS 0x0002 /* fs has errors. */ + +#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) +#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) + +#define MINIX_V1 0x0001 /* original minix fs */ +#define MINIX_V2 0x0002 /* minix V2 fs */ + +/* originally this is : +#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version + here we have */ +#define INODE_VERSION(inode) (SUPERBLOCK->s_version) + +/* + * This is the original minix inode layout on disk. + * Note the 8-bit gid and atime and ctime. + */ +struct minix_inode { + __u16 i_mode; + __u16 i_uid; + __u32 i_size; + __u32 i_time; + __u8 i_gid; + __u8 i_nlinks; + __u16 i_zone[9]; +}; + +/* + * The new minix inode has all the time entries, as well as + * long block numbers and a third indirect block (7+1+1+1 + * instead of 7+1+1). Also, some previously 8-bit values are + * now 16-bit. The inode is now 64 bytes instead of 32. + */ +struct minix2_inode { + __u16 i_mode; + __u16 i_nlinks; + __u16 i_uid; + __u16 i_gid; + __u32 i_size; + __u32 i_atime; + __u32 i_mtime; + __u32 i_ctime; + __u32 i_zone[10]; +}; + +/* + * minix super-block data on disk + */ +struct minix_super_block { + __u16 s_ninodes; + __u16 s_nzones; + __u16 s_imap_blocks; + __u16 s_zmap_blocks; + __u16 s_firstdatazone; + __u16 s_log_zone_size; + __u32 s_max_size; + __u16 s_magic; + __u16 s_state; + __u32 s_zones; +}; + +struct minix_dir_entry { + __u16 inode; + char name[0]; +}; + +/* made up, these are pointers into FSYS_BUF */ +/* read once, always stays there: */ +#define SUPERBLOCK \ + ((struct minix_super_block *)(FSYS_BUF)) +#define INODE \ + ((struct minix_inode *)((char *) SUPERBLOCK + BLOCK_SIZE)) +#define DATABLOCK1 \ + ((char *)((char *)INODE + sizeof(struct minix_inode))) +#define DATABLOCK2 \ + ((char *)((char *)DATABLOCK1 + BLOCK_SIZE)) + +/* linux/stat.h */ +#define S_IFMT 00170000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFDIR 0040000 +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) + +#define PATH_MAX 1024 /* include/linux/limits.h */ +#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */ + +/* check filesystem types and read superblock into memory buffer */ +int +minix_mount (void) +{ + if (((current_drive & 0x80) || current_slice != 0) + && ! IS_PC_SLICE_TYPE_MINIX (current_slice) + && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER)) + return 0; /* The partition is not of MINIX type */ + + if (part_length < (SBLOCK + + (sizeof (struct minix_super_block) / DEV_BSIZE))) + return 0; /* The partition is too short */ + + if (!devread (SBLOCK, 0, sizeof (struct minix_super_block), + (char *) SUPERBLOCK)) + return 0; /* Cannot read superblock */ + + switch (SUPERBLOCK->s_magic) + { + case MINIX_SUPER_MAGIC: + namelen = 14; + break; + case MINIX_SUPER_MAGIC2: + namelen = 30; + break; + default: + return 0; /* Unsupported type */ + } + + return 1; +} + +/* Takes a file system block number and reads it into BUFFER. */ +static int +minix_rdfsb (int fsblock, char *buffer) +{ + return devread (fsblock * (BLOCK_SIZE / DEV_BSIZE), 0, + BLOCK_SIZE, buffer); +} + +/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into + a physical block (the location in the file system) via an inode. */ +static int +minix_block_map (int logical_block) +{ + int i; + + if (logical_block < 7) + return INODE->i_zone[logical_block]; + + logical_block -= 7; + if (logical_block < 512) + { + i = INODE->i_zone[7]; + + if (!i || ((mapblock1 != 1) + && !minix_rdfsb (i, DATABLOCK1))) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock1 = 1; + return ((__u16 *) DATABLOCK1) [logical_block]; + } + + logical_block -= 512; + i = INODE->i_zone[8]; + if (!i || ((mapblock1 != 2) + && !minix_rdfsb (i, DATABLOCK1))) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock1 = 2; + i = ((__u16 *) DATABLOCK1)[logical_block >> 9]; + if (!i || ((mapblock2 != i) + && !minix_rdfsb (i, DATABLOCK2))) + { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock2 = i; + return ((__u16 *) DATABLOCK2)[logical_block & 511]; +} + +/* read from INODE into BUF */ +int +minix_read (char *buf, int len) +{ + int logical_block; + int offset; + int map; + int ret = 0; + int size = 0; + + while (len > 0) + { + /* find the (logical) block component of our location */ + logical_block = filepos >> BLOCK_SIZE_BITS; + offset = filepos & (BLOCK_SIZE - 1); + map = minix_block_map (logical_block); +#ifdef DEBUG_MINIX + printf ("map=%d\n", map); +#endif + if (map < 0) + break; + + size = BLOCK_SIZE; + size -= offset; + if (size > len) + size = len; + + disk_read_func = disk_read_hook; + + devread (map * (BLOCK_SIZE / DEV_BSIZE), + offset, size, buf); + + disk_read_func = NULL; + + buf += size; + len -= size; + filepos += size; + ret += size; + } + + if (errnum) + ret = 0; + + return ret; +} + +/* preconditions: minix_mount already executed, therefore supblk in buffer + known as SUPERBLOCK + returns: 0 if error, nonzero iff we were able to find the file successfully + postconditions: on a nonzero return, buffer known as INODE contains the + inode of the file we were trying to look up + side effects: none yet */ +int +minix_dir (char *dirname) +{ + int current_ino = MINIX_ROOT_INO; /* start at the root */ + int updir_ino = current_ino; /* the parent of the current directory */ + int ino_blk; /* fs pointer of the inode's info */ + + int str_chk = 0; /* used ot hold the results of a string + compare */ + + struct minix_inode * raw_inode; /* inode info for current_ino */ + + char linkbuf[PATH_MAX]; /* buffer for following sym-links */ + int link_count = 0; + + char * rest; + char ch; + + int off; /* offset within block of directory + entry */ + int loc; /* location within a directory */ + int blk; /* which data blk within dir entry */ + long map; /* fs pointer of a particular block from + dir entry */ + struct minix_dir_entry * dp; /* pointer to directory entry */ + + /* loop invariants: + current_ino = inode to lookup + dirname = pointer to filename component we are cur looking up within + the directory known pointed to by current_ino (if any) */ + +#ifdef DEBUG_MINIX + printf ("\n"); +#endif + + while (1) + { +#ifdef DEBUG_MINIX + printf ("inode %d, dirname %s\n", current_ino, dirname); +#endif + + ino_blk = (2 + SUPERBLOCK->s_imap_blocks + SUPERBLOCK->s_zmap_blocks + + (current_ino - 1) / MINIX_INODES_PER_BLOCK); + if (! minix_rdfsb (ino_blk, (char *) INODE)) + return 0; + + /* reset indirect blocks! */ + mapblock2 = mapblock1 = -1; + + raw_inode = INODE + ((current_ino - 1) % MINIX_INODES_PER_BLOCK); + + /* copy inode to fixed location */ + memmove ((void *) INODE, (void *) raw_inode, + sizeof (struct minix_inode)); + + /* If we've got a symbolic link, then chase it. */ + if (S_ISLNK (INODE->i_mode)) + { + int len; + + if (++link_count > MAX_LINK_COUNT) + { + errnum = ERR_SYMLINK_LOOP; + return 0; + } +#ifdef DEBUG_MINIX + printf ("S_ISLNK (%s)\n", dirname); +#endif + + /* Find out how long our remaining name is. */ + len = 0; + while (dirname[len] && !isspace (dirname[len])) + len++; + + /* Get the symlink size. */ + filemax = (INODE->i_size); + if (filemax + len > sizeof (linkbuf) - 2) + { + errnum = ERR_FILELENGTH; + return 0; + } + + if (len) + { + /* Copy the remaining name to the end of the symlink data. + Note that DIRNAME and LINKBUF may overlap! */ + memmove (linkbuf + filemax, dirname, len); + } + linkbuf[filemax + len] = '\0'; + + /* Read the necessary blocks, and reset the file pointer. */ + len = grub_read (linkbuf, filemax); + filepos = 0; + if (!len) + return 0; + +#ifdef DEBUG_MINIX + printf ("symlink=%s\n", linkbuf); +#endif + + dirname = linkbuf; + if (*dirname == '/') + { + /* It's an absolute link, so look it up in root. */ + current_ino = MINIX_ROOT_INO; + updir_ino = current_ino; + } + else + { + /* Relative, so look it up in our parent directory. */ + current_ino = updir_ino; + } + + /* Try again using the new name. */ + continue; + } + + /* If end of filename, INODE points to the file's inode */ + if (!*dirname || isspace (*dirname)) + { + if (!S_ISREG (INODE->i_mode)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + filemax = (INODE->i_size); + return 1; + } + + /* else we have to traverse a directory */ + updir_ino = current_ino; + + /* skip over slashes */ + while (*dirname == '/') + dirname++; + + /* if this isn't a directory of sufficient size to hold our file, + abort */ + if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + /* skip to next slash or end of filename (space) */ + for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; + rest++); + + /* look through this directory and find the next filename component */ + /* invariant: rest points to slash after the next filename component */ + *rest = 0; + loc = 0; + + do + { +#ifdef DEBUG_MINIX + printf ("dirname=`%s', rest=`%s', loc=%d\n", dirname, rest, loc); +#endif + + /* if our location/byte offset into the directory exceeds the size, + give up */ + if (loc >= INODE->i_size) + { + if (print_possibilities < 0) + { +#if 0 + putchar ('\n'); +#endif + } + else + { + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + } + return (print_possibilities < 0); + } + + /* else, find the (logical) block component of our location */ + blk = loc >> BLOCK_SIZE_BITS; + + /* we know which logical block of the directory entry we are looking + for, now we have to translate that to the physical (fs) block on + the disk */ + map = minix_block_map (blk); +#ifdef DEBUG_MINIX + printf ("fs block=%d\n", map); +#endif + mapblock2 = -1; + if ((map < 0) || !minix_rdfsb (map, DATABLOCK2)) + { + errnum = ERR_FSYS_CORRUPT; + *rest = ch; + return 0; + } + off = loc & (BLOCK_SIZE - 1); + dp = (struct minix_dir_entry *) (DATABLOCK2 + off); + /* advance loc prematurely to next on-disk directory entry */ + loc += sizeof (dp->inode) + namelen; + + /* NOTE: minix filenames are NULL terminated if < NAMELEN + else exact */ + +#ifdef DEBUG_MINIX + printf ("directory entry ino=%d\n", dp->inode); + if (dp->inode) + printf ("entry=%s\n", dp->name); +#endif + + if (dp->inode) + { + int saved_c = dp->name[namelen]; + + dp->name[namelen] = 0; + str_chk = substring (dirname, dp->name); + +# ifndef STAGE1_5 + if (print_possibilities && ch != '/' + && (!*dirname || str_chk <= 0)) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + print_a_completion (dp->name); + } +# endif + + dp->name[namelen] = saved_c; + } + + } + while (!dp->inode || (str_chk || (print_possibilities && ch != '/'))); + + current_ino = dp->inode; + *(dirname = rest) = ch; + } + /* never get here */ +} + +#endif /* FSYS_MINIX */