17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  *  GRUB  --  GRand Unified Bootloader
37c478bd9Sstevel@tonic-gate  *  Copyright (C) 1999,2000,2001,2002  Free Software Foundation, Inc.
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  *  This program is free software; you can redistribute it and/or modify
67c478bd9Sstevel@tonic-gate  *  it under the terms of the GNU General Public License as published by
77c478bd9Sstevel@tonic-gate  *  the Free Software Foundation; either version 2 of the License, or
87c478bd9Sstevel@tonic-gate  *  (at your option) any later version.
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  *  This program is distributed in the hope that it will be useful,
117c478bd9Sstevel@tonic-gate  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
127c478bd9Sstevel@tonic-gate  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
137c478bd9Sstevel@tonic-gate  *  GNU General Public License for more details.
147c478bd9Sstevel@tonic-gate  *
157c478bd9Sstevel@tonic-gate  *  You should have received a copy of the GNU General Public License
167c478bd9Sstevel@tonic-gate  *  along with this program; if not, write to the Free Software
177c478bd9Sstevel@tonic-gate  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
187c478bd9Sstevel@tonic-gate  */
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate /* Restrictions:
217c478bd9Sstevel@tonic-gate    This is MINIX V1 only (yet)
227c478bd9Sstevel@tonic-gate    Disk creation is like:
237c478bd9Sstevel@tonic-gate    mkfs.minix -c DEVICE
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #ifdef FSYS_MINIX
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include "shared.h"
297c478bd9Sstevel@tonic-gate #include "filesys.h"
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /* #define DEBUG_MINIX */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /* indirect blocks */
347c478bd9Sstevel@tonic-gate static int mapblock1, mapblock2, namelen;
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate /* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
377c478bd9Sstevel@tonic-gate #define DEV_BSIZE 512
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /* include/linux/fs.h */
407c478bd9Sstevel@tonic-gate #define BLOCK_SIZE_BITS 10
417c478bd9Sstevel@tonic-gate #define BLOCK_SIZE 	(1<<BLOCK_SIZE_BITS)
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /* made up, defaults to 1 but can be passed via mount_opts */
447c478bd9Sstevel@tonic-gate #define WHICH_SUPER 1
457c478bd9Sstevel@tonic-gate /* kind of from fs/ext2/super.c (is OK for minix) */
467c478bd9Sstevel@tonic-gate #define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE)	/* = 2 */
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /* include/asm-i386/type.h */
497c478bd9Sstevel@tonic-gate typedef __signed__ char __s8;
507c478bd9Sstevel@tonic-gate typedef unsigned char __u8;
517c478bd9Sstevel@tonic-gate typedef __signed__ short __s16;
527c478bd9Sstevel@tonic-gate typedef unsigned short __u16;
537c478bd9Sstevel@tonic-gate typedef __signed__ int __s32;
547c478bd9Sstevel@tonic-gate typedef unsigned int __u32;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /* include/linux/minix_fs.h */
577c478bd9Sstevel@tonic-gate #define MINIX_ROOT_INO 1
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
607c478bd9Sstevel@tonic-gate #define MINIX_LINK_MAX  250
617c478bd9Sstevel@tonic-gate #define MINIX2_LINK_MAX 65530
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate #define MINIX_I_MAP_SLOTS       8
647c478bd9Sstevel@tonic-gate #define MINIX_Z_MAP_SLOTS       64
657c478bd9Sstevel@tonic-gate #define MINIX_SUPER_MAGIC       0x137F          /* original minix fs */
667c478bd9Sstevel@tonic-gate #define MINIX_SUPER_MAGIC2      0x138F          /* minix fs, 30 char names */
677c478bd9Sstevel@tonic-gate #define MINIX2_SUPER_MAGIC      0x2468          /* minix V2 fs */
687c478bd9Sstevel@tonic-gate #define MINIX2_SUPER_MAGIC2     0x2478          /* minix V2 fs, 30 char names */
697c478bd9Sstevel@tonic-gate #define MINIX_VALID_FS          0x0001          /* Clean fs. */
707c478bd9Sstevel@tonic-gate #define MINIX_ERROR_FS          0x0002          /* fs has errors. */
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
737c478bd9Sstevel@tonic-gate #define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #define MINIX_V1                0x0001          /* original minix fs */
767c478bd9Sstevel@tonic-gate #define MINIX_V2                0x0002          /* minix V2 fs */
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /* originally this is :
797c478bd9Sstevel@tonic-gate #define INODE_VERSION(inode)    inode->i_sb->u.minix_sb.s_version
807c478bd9Sstevel@tonic-gate    here we have */
817c478bd9Sstevel@tonic-gate #define INODE_VERSION(inode)	(SUPERBLOCK->s_version)
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * This is the original minix inode layout on disk.
857c478bd9Sstevel@tonic-gate  * Note the 8-bit gid and atime and ctime.
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate struct minix_inode {
887c478bd9Sstevel@tonic-gate 	__u16 i_mode;
897c478bd9Sstevel@tonic-gate 	__u16 i_uid;
907c478bd9Sstevel@tonic-gate 	__u32 i_size;
917c478bd9Sstevel@tonic-gate 	__u32 i_time;
927c478bd9Sstevel@tonic-gate 	__u8  i_gid;
937c478bd9Sstevel@tonic-gate 	__u8  i_nlinks;
947c478bd9Sstevel@tonic-gate 	__u16 i_zone[9];
957c478bd9Sstevel@tonic-gate };
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * The new minix inode has all the time entries, as well as
997c478bd9Sstevel@tonic-gate  * long block numbers and a third indirect block (7+1+1+1
1007c478bd9Sstevel@tonic-gate  * instead of 7+1+1). Also, some previously 8-bit values are
1017c478bd9Sstevel@tonic-gate  * now 16-bit. The inode is now 64 bytes instead of 32.
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate struct minix2_inode {
1047c478bd9Sstevel@tonic-gate 	__u16 i_mode;
1057c478bd9Sstevel@tonic-gate 	__u16 i_nlinks;
1067c478bd9Sstevel@tonic-gate 	__u16 i_uid;
1077c478bd9Sstevel@tonic-gate 	__u16 i_gid;
1087c478bd9Sstevel@tonic-gate 	__u32 i_size;
1097c478bd9Sstevel@tonic-gate 	__u32 i_atime;
1107c478bd9Sstevel@tonic-gate 	__u32 i_mtime;
1117c478bd9Sstevel@tonic-gate 	__u32 i_ctime;
1127c478bd9Sstevel@tonic-gate 	__u32 i_zone[10];
1137c478bd9Sstevel@tonic-gate };
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate  * minix super-block data on disk
1177c478bd9Sstevel@tonic-gate  */
1187c478bd9Sstevel@tonic-gate struct minix_super_block {
1197c478bd9Sstevel@tonic-gate         __u16 s_ninodes;
1207c478bd9Sstevel@tonic-gate         __u16 s_nzones;
1217c478bd9Sstevel@tonic-gate         __u16 s_imap_blocks;
1227c478bd9Sstevel@tonic-gate         __u16 s_zmap_blocks;
1237c478bd9Sstevel@tonic-gate         __u16 s_firstdatazone;
1247c478bd9Sstevel@tonic-gate         __u16 s_log_zone_size;
1257c478bd9Sstevel@tonic-gate         __u32 s_max_size;
1267c478bd9Sstevel@tonic-gate         __u16 s_magic;
1277c478bd9Sstevel@tonic-gate         __u16 s_state;
1287c478bd9Sstevel@tonic-gate         __u32 s_zones;
1297c478bd9Sstevel@tonic-gate };
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate struct minix_dir_entry {
1327c478bd9Sstevel@tonic-gate         __u16 inode;
1337c478bd9Sstevel@tonic-gate         char name[0];
1347c478bd9Sstevel@tonic-gate };
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate /* made up, these are pointers into FSYS_BUF */
1377c478bd9Sstevel@tonic-gate /* read once, always stays there: */
1387c478bd9Sstevel@tonic-gate #define SUPERBLOCK \
1397c478bd9Sstevel@tonic-gate     ((struct minix_super_block *)(FSYS_BUF))
1407c478bd9Sstevel@tonic-gate #define INODE \
1417c478bd9Sstevel@tonic-gate     ((struct minix_inode *)((int) SUPERBLOCK + BLOCK_SIZE))
1427c478bd9Sstevel@tonic-gate #define DATABLOCK1 \
1437c478bd9Sstevel@tonic-gate     ((int)((int)INODE + sizeof(struct minix_inode)))
1447c478bd9Sstevel@tonic-gate #define DATABLOCK2 \
1457c478bd9Sstevel@tonic-gate     ((int)((int)DATABLOCK1 + BLOCK_SIZE))
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /* linux/stat.h */
1487c478bd9Sstevel@tonic-gate #define S_IFMT  00170000
1497c478bd9Sstevel@tonic-gate #define S_IFLNK  0120000
1507c478bd9Sstevel@tonic-gate #define S_IFREG  0100000
1517c478bd9Sstevel@tonic-gate #define S_IFDIR  0040000
1527c478bd9Sstevel@tonic-gate #define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
1537c478bd9Sstevel@tonic-gate #define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
1547c478bd9Sstevel@tonic-gate #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate #define PATH_MAX                1024	/* include/linux/limits.h */
1577c478bd9Sstevel@tonic-gate #define MAX_LINK_COUNT             5	/* number of symbolic links to follow */
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /* check filesystem types and read superblock into memory buffer */
1607c478bd9Sstevel@tonic-gate int
minix_mount(void)1617c478bd9Sstevel@tonic-gate minix_mount (void)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate   if (((current_drive & 0x80) || current_slice != 0)
1647c478bd9Sstevel@tonic-gate       && ! IS_PC_SLICE_TYPE_MINIX (current_slice)
1657c478bd9Sstevel@tonic-gate       && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))
1667c478bd9Sstevel@tonic-gate     return 0;			/* The partition is not of MINIX type */
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate   if (part_length < (SBLOCK +
1697c478bd9Sstevel@tonic-gate 		     (sizeof (struct minix_super_block) / DEV_BSIZE)))
1707c478bd9Sstevel@tonic-gate     return 0;			/* The partition is too short */
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate   if (!devread (SBLOCK, 0, sizeof (struct minix_super_block),
1737c478bd9Sstevel@tonic-gate 		(char *) SUPERBLOCK))
1747c478bd9Sstevel@tonic-gate     return 0;			/* Cannot read superblock */
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate   switch (SUPERBLOCK->s_magic)
1777c478bd9Sstevel@tonic-gate     {
1787c478bd9Sstevel@tonic-gate     case MINIX_SUPER_MAGIC:
1797c478bd9Sstevel@tonic-gate       namelen = 14;
1807c478bd9Sstevel@tonic-gate       break;
1817c478bd9Sstevel@tonic-gate     case MINIX_SUPER_MAGIC2:
1827c478bd9Sstevel@tonic-gate       namelen = 30;
1837c478bd9Sstevel@tonic-gate       break;
1847c478bd9Sstevel@tonic-gate     default:
1857c478bd9Sstevel@tonic-gate       return 0;			/* Unsupported type */
1867c478bd9Sstevel@tonic-gate     }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate   return 1;
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate /* Takes a file system block number and reads it into BUFFER. */
1927c478bd9Sstevel@tonic-gate static int
minix_rdfsb(int fsblock,int buffer)1937c478bd9Sstevel@tonic-gate minix_rdfsb (int fsblock, int buffer)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate   return devread (fsblock * (BLOCK_SIZE / DEV_BSIZE), 0,
1967c478bd9Sstevel@tonic-gate 		  BLOCK_SIZE, (char *) buffer);
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate /* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
2007c478bd9Sstevel@tonic-gate    a physical block (the location in the file system) via an inode. */
2017c478bd9Sstevel@tonic-gate static int
minix_block_map(int logical_block)2027c478bd9Sstevel@tonic-gate minix_block_map (int logical_block)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate   int i;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate   if (logical_block < 7)
2077c478bd9Sstevel@tonic-gate     return INODE->i_zone[logical_block];
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate   logical_block -= 7;
2107c478bd9Sstevel@tonic-gate   if (logical_block < 512)
2117c478bd9Sstevel@tonic-gate     {
2127c478bd9Sstevel@tonic-gate       i = INODE->i_zone[7];
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate       if (!i || ((mapblock1 != 1)
2157c478bd9Sstevel@tonic-gate 		 && !minix_rdfsb (i, DATABLOCK1)))
2167c478bd9Sstevel@tonic-gate 	{
2177c478bd9Sstevel@tonic-gate 	  errnum = ERR_FSYS_CORRUPT;
2187c478bd9Sstevel@tonic-gate 	  return -1;
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate       mapblock1 = 1;
2217c478bd9Sstevel@tonic-gate       return ((__u16 *) DATABLOCK1) [logical_block];
2227c478bd9Sstevel@tonic-gate     }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate   logical_block -= 512;
2257c478bd9Sstevel@tonic-gate   i = INODE->i_zone[8];
2267c478bd9Sstevel@tonic-gate   if (!i || ((mapblock1 != 2)
2277c478bd9Sstevel@tonic-gate 	     && !minix_rdfsb (i, DATABLOCK1)))
2287c478bd9Sstevel@tonic-gate     {
2297c478bd9Sstevel@tonic-gate       errnum = ERR_FSYS_CORRUPT;
2307c478bd9Sstevel@tonic-gate       return -1;
2317c478bd9Sstevel@tonic-gate     }
2327c478bd9Sstevel@tonic-gate   mapblock1 = 2;
2337c478bd9Sstevel@tonic-gate   i = ((__u16 *) DATABLOCK1)[logical_block >> 9];
2347c478bd9Sstevel@tonic-gate   if (!i || ((mapblock2 != i)
2357c478bd9Sstevel@tonic-gate 	     && !minix_rdfsb (i, DATABLOCK2)))
2367c478bd9Sstevel@tonic-gate     {
2377c478bd9Sstevel@tonic-gate       errnum = ERR_FSYS_CORRUPT;
2387c478bd9Sstevel@tonic-gate       return -1;
2397c478bd9Sstevel@tonic-gate     }
2407c478bd9Sstevel@tonic-gate   mapblock2 = i;
2417c478bd9Sstevel@tonic-gate   return ((__u16 *) DATABLOCK2)[logical_block & 511];
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate /* read from INODE into BUF */
2457c478bd9Sstevel@tonic-gate int
minix_read(char * buf,int len)2467c478bd9Sstevel@tonic-gate minix_read (char *buf, int len)
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate   int logical_block;
2497c478bd9Sstevel@tonic-gate   int offset;
2507c478bd9Sstevel@tonic-gate   int map;
2517c478bd9Sstevel@tonic-gate   int ret = 0;
2527c478bd9Sstevel@tonic-gate   int size = 0;
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate   while (len > 0)
2557c478bd9Sstevel@tonic-gate     {
2567c478bd9Sstevel@tonic-gate       /* find the (logical) block component of our location */
2577c478bd9Sstevel@tonic-gate       logical_block = filepos >> BLOCK_SIZE_BITS;
2587c478bd9Sstevel@tonic-gate       offset = filepos & (BLOCK_SIZE - 1);
2597c478bd9Sstevel@tonic-gate       map = minix_block_map (logical_block);
2607c478bd9Sstevel@tonic-gate #ifdef DEBUG_MINIX
2617c478bd9Sstevel@tonic-gate       printf ("map=%d\n", map);
2627c478bd9Sstevel@tonic-gate #endif
2637c478bd9Sstevel@tonic-gate       if (map < 0)
2647c478bd9Sstevel@tonic-gate 	break;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate       size = BLOCK_SIZE;
2677c478bd9Sstevel@tonic-gate       size -= offset;
2687c478bd9Sstevel@tonic-gate       if (size > len)
2697c478bd9Sstevel@tonic-gate 	size = len;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate       disk_read_func = disk_read_hook;
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate       devread (map * (BLOCK_SIZE / DEV_BSIZE),
2747c478bd9Sstevel@tonic-gate 	       offset, size, buf);
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate       disk_read_func = NULL;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate       buf += size;
2797c478bd9Sstevel@tonic-gate       len -= size;
2807c478bd9Sstevel@tonic-gate       filepos += size;
2817c478bd9Sstevel@tonic-gate       ret += size;
2827c478bd9Sstevel@tonic-gate     }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate   if (errnum)
2857c478bd9Sstevel@tonic-gate     ret = 0;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate   return ret;
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate /* preconditions: minix_mount already executed, therefore supblk in buffer
2917c478bd9Sstevel@tonic-gate      known as SUPERBLOCK
2927c478bd9Sstevel@tonic-gate    returns: 0 if error, nonzero iff we were able to find the file successfully
2937c478bd9Sstevel@tonic-gate    postconditions: on a nonzero return, buffer known as INODE contains the
2947c478bd9Sstevel@tonic-gate      inode of the file we were trying to look up
2957c478bd9Sstevel@tonic-gate    side effects: none yet  */
2967c478bd9Sstevel@tonic-gate int
minix_dir(char * dirname)2977c478bd9Sstevel@tonic-gate minix_dir (char *dirname)
2987c478bd9Sstevel@tonic-gate {
2997c478bd9Sstevel@tonic-gate   int current_ino = MINIX_ROOT_INO;  /* start at the root */
3007c478bd9Sstevel@tonic-gate   int updir_ino = current_ino;	     /* the parent of the current directory */
3017c478bd9Sstevel@tonic-gate   int ino_blk;			     /* fs pointer of the inode's info */
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate   int str_chk = 0;		     /* used ot hold the results of a string
3047c478bd9Sstevel@tonic-gate 				        compare */
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate   struct minix_inode * raw_inode;    /* inode info for current_ino */
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate   char linkbuf[PATH_MAX];	     /* buffer for following sym-links */
3097c478bd9Sstevel@tonic-gate   int link_count = 0;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate   char * rest;
3127c478bd9Sstevel@tonic-gate   char ch;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate   int off;			     /* offset within block of directory
3157c478bd9Sstevel@tonic-gate 					entry */
3167c478bd9Sstevel@tonic-gate   int loc;			     /* location within a directory */
3177c478bd9Sstevel@tonic-gate   int blk;			     /* which data blk within dir entry */
3187c478bd9Sstevel@tonic-gate   long map;			     /* fs pointer of a particular block from
3197c478bd9Sstevel@tonic-gate 					dir entry */
3207c478bd9Sstevel@tonic-gate   struct minix_dir_entry * dp;	     /* pointer to directory entry */
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate   /* loop invariants:
3237c478bd9Sstevel@tonic-gate      current_ino = inode to lookup
3247c478bd9Sstevel@tonic-gate      dirname = pointer to filename component we are cur looking up within
3257c478bd9Sstevel@tonic-gate      the directory known pointed to by current_ino (if any) */
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate #ifdef DEBUG_MINIX
3287c478bd9Sstevel@tonic-gate   printf ("\n");
3297c478bd9Sstevel@tonic-gate #endif
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate   while (1)
3327c478bd9Sstevel@tonic-gate     {
3337c478bd9Sstevel@tonic-gate #ifdef DEBUG_MINIX
3347c478bd9Sstevel@tonic-gate       printf ("inode %d, dirname %s\n", current_ino, dirname);
3357c478bd9Sstevel@tonic-gate #endif
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate       ino_blk = (2 + SUPERBLOCK->s_imap_blocks + SUPERBLOCK->s_zmap_blocks
3387c478bd9Sstevel@tonic-gate 		 + (current_ino - 1) / MINIX_INODES_PER_BLOCK);
3397c478bd9Sstevel@tonic-gate       if (! minix_rdfsb (ino_blk, (int) INODE))
3407c478bd9Sstevel@tonic-gate 	return 0;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate       /* reset indirect blocks! */
3437c478bd9Sstevel@tonic-gate       mapblock2 = mapblock1 = -1;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate       raw_inode = INODE + ((current_ino - 1) % MINIX_INODES_PER_BLOCK);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate       /* copy inode to fixed location */
3487c478bd9Sstevel@tonic-gate       memmove ((void *) INODE, (void *) raw_inode,
3497c478bd9Sstevel@tonic-gate 	       sizeof (struct minix_inode));
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate       /* If we've got a symbolic link, then chase it. */
3527c478bd9Sstevel@tonic-gate       if (S_ISLNK (INODE->i_mode))
3537c478bd9Sstevel@tonic-gate 	{
3547c478bd9Sstevel@tonic-gate 	  int len;
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	  if (++link_count > MAX_LINK_COUNT)
3577c478bd9Sstevel@tonic-gate 	    {
3587c478bd9Sstevel@tonic-gate 	      errnum = ERR_SYMLINK_LOOP;
3597c478bd9Sstevel@tonic-gate 	      return 0;
3607c478bd9Sstevel@tonic-gate 	    }
3617c478bd9Sstevel@tonic-gate #ifdef DEBUG_MINIX
3627c478bd9Sstevel@tonic-gate 	  printf ("S_ISLNK (%s)\n", dirname);
3637c478bd9Sstevel@tonic-gate #endif
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	  /* Find out how long our remaining name is. */
3667c478bd9Sstevel@tonic-gate 	  len = 0;
3677c478bd9Sstevel@tonic-gate 	  while (dirname[len] && !isspace (dirname[len]))
3687c478bd9Sstevel@tonic-gate 	    len++;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	  /* Get the symlink size. */
3717c478bd9Sstevel@tonic-gate 	  filemax = (INODE->i_size);
3727c478bd9Sstevel@tonic-gate 	  if (filemax + len > sizeof (linkbuf) - 2)
3737c478bd9Sstevel@tonic-gate 	    {
3747c478bd9Sstevel@tonic-gate 	      errnum = ERR_FILELENGTH;
3757c478bd9Sstevel@tonic-gate 	      return 0;
3767c478bd9Sstevel@tonic-gate 	    }
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	  if (len)
3797c478bd9Sstevel@tonic-gate 	    {
3807c478bd9Sstevel@tonic-gate 	      /* Copy the remaining name to the end of the symlink data.
3817c478bd9Sstevel@tonic-gate 	         Note that DIRNAME and LINKBUF may overlap! */
3827c478bd9Sstevel@tonic-gate 	      memmove (linkbuf + filemax, dirname, len);
3837c478bd9Sstevel@tonic-gate 	    }
3847c478bd9Sstevel@tonic-gate 	  linkbuf[filemax + len] = '\0';
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	  /* Read the necessary blocks, and reset the file pointer. */
3877c478bd9Sstevel@tonic-gate 	  len = grub_read (linkbuf, filemax);
3887c478bd9Sstevel@tonic-gate 	  filepos = 0;
3897c478bd9Sstevel@tonic-gate 	  if (!len)
3907c478bd9Sstevel@tonic-gate 	    return 0;
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate #ifdef DEBUG_MINIX
3937c478bd9Sstevel@tonic-gate 	  printf ("symlink=%s\n", linkbuf);
3947c478bd9Sstevel@tonic-gate #endif
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	  dirname = linkbuf;
3977c478bd9Sstevel@tonic-gate 	  if (*dirname == '/')
3987c478bd9Sstevel@tonic-gate 	    {
3997c478bd9Sstevel@tonic-gate 	      /* It's an absolute link, so look it up in root. */
4007c478bd9Sstevel@tonic-gate 	      current_ino = MINIX_ROOT_INO;
4017c478bd9Sstevel@tonic-gate 	      updir_ino = current_ino;
4027c478bd9Sstevel@tonic-gate 	    }
4037c478bd9Sstevel@tonic-gate 	  else
4047c478bd9Sstevel@tonic-gate 	    {
4057c478bd9Sstevel@tonic-gate 	      /* Relative, so look it up in our parent directory. */
4067c478bd9Sstevel@tonic-gate 	      current_ino = updir_ino;
4077c478bd9Sstevel@tonic-gate 	    }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	  /* Try again using the new name. */
4107c478bd9Sstevel@tonic-gate 	  continue;
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate       /* If end of filename, INODE points to the file's inode */
4147c478bd9Sstevel@tonic-gate       if (!*dirname || isspace (*dirname))
4157c478bd9Sstevel@tonic-gate 	{
4167c478bd9Sstevel@tonic-gate 	  if (!S_ISREG (INODE->i_mode))
4177c478bd9Sstevel@tonic-gate 	    {
4187c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_FILETYPE;
4197c478bd9Sstevel@tonic-gate 	      return 0;
4207c478bd9Sstevel@tonic-gate 	    }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	  filemax = (INODE->i_size);
4237c478bd9Sstevel@tonic-gate 	  return 1;
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate       /* else we have to traverse a directory */
4277c478bd9Sstevel@tonic-gate       updir_ino = current_ino;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate       /* skip over slashes */
4307c478bd9Sstevel@tonic-gate       while (*dirname == '/')
4317c478bd9Sstevel@tonic-gate 	dirname++;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate       /* if this isn't a directory of sufficient size to hold our file,
4347c478bd9Sstevel@tonic-gate 	 abort */
4357c478bd9Sstevel@tonic-gate       if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode))
4367c478bd9Sstevel@tonic-gate 	{
4377c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_FILETYPE;
4387c478bd9Sstevel@tonic-gate 	  return 0;
4397c478bd9Sstevel@tonic-gate 	}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate       /* skip to next slash or end of filename (space) */
4427c478bd9Sstevel@tonic-gate       for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
4437c478bd9Sstevel@tonic-gate 	   rest++);
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate       /* look through this directory and find the next filename component */
4467c478bd9Sstevel@tonic-gate       /* invariant: rest points to slash after the next filename component */
4477c478bd9Sstevel@tonic-gate       *rest = 0;
4487c478bd9Sstevel@tonic-gate       loc = 0;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate       do
4517c478bd9Sstevel@tonic-gate 	{
4527c478bd9Sstevel@tonic-gate #ifdef DEBUG_MINIX
4537c478bd9Sstevel@tonic-gate 	  printf ("dirname=`%s', rest=`%s', loc=%d\n", dirname, rest, loc);
4547c478bd9Sstevel@tonic-gate #endif
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	  /* if our location/byte offset into the directory exceeds the size,
4577c478bd9Sstevel@tonic-gate 	     give up */
4587c478bd9Sstevel@tonic-gate 	  if (loc >= INODE->i_size)
4597c478bd9Sstevel@tonic-gate 	    {
4607c478bd9Sstevel@tonic-gate 	      if (print_possibilities < 0)
4617c478bd9Sstevel@tonic-gate 		{
4627c478bd9Sstevel@tonic-gate #if 0
4637c478bd9Sstevel@tonic-gate 		  putchar ('\n');
4647c478bd9Sstevel@tonic-gate #endif
4657c478bd9Sstevel@tonic-gate 		}
4667c478bd9Sstevel@tonic-gate 	      else
4677c478bd9Sstevel@tonic-gate 		{
4687c478bd9Sstevel@tonic-gate 		  errnum = ERR_FILE_NOT_FOUND;
4697c478bd9Sstevel@tonic-gate 		  *rest = ch;
4707c478bd9Sstevel@tonic-gate 		}
4717c478bd9Sstevel@tonic-gate 	      return (print_possibilities < 0);
4727c478bd9Sstevel@tonic-gate 	    }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	  /* else, find the (logical) block component of our location */
4757c478bd9Sstevel@tonic-gate 	  blk = loc >> BLOCK_SIZE_BITS;
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	  /* we know which logical block of the directory entry we are looking
4787c478bd9Sstevel@tonic-gate 	     for, now we have to translate that to the physical (fs) block on
4797c478bd9Sstevel@tonic-gate 	     the disk */
4807c478bd9Sstevel@tonic-gate 	  map = minix_block_map (blk);
4817c478bd9Sstevel@tonic-gate #ifdef DEBUG_MINIX
4827c478bd9Sstevel@tonic-gate 	  printf ("fs block=%d\n", map);
4837c478bd9Sstevel@tonic-gate #endif
4847c478bd9Sstevel@tonic-gate 	  mapblock2 = -1;
4857c478bd9Sstevel@tonic-gate 	  if ((map < 0) || !minix_rdfsb (map, DATABLOCK2))
4867c478bd9Sstevel@tonic-gate 	    {
4877c478bd9Sstevel@tonic-gate 	      errnum = ERR_FSYS_CORRUPT;
4887c478bd9Sstevel@tonic-gate 	      *rest = ch;
4897c478bd9Sstevel@tonic-gate 	      return 0;
4907c478bd9Sstevel@tonic-gate 	    }
4917c478bd9Sstevel@tonic-gate 	  off = loc & (BLOCK_SIZE - 1);
4927c478bd9Sstevel@tonic-gate 	  dp = (struct minix_dir_entry *) (DATABLOCK2 + off);
4937c478bd9Sstevel@tonic-gate 	  /* advance loc prematurely to next on-disk directory entry  */
4947c478bd9Sstevel@tonic-gate 	  loc += sizeof (dp->inode) + namelen;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	  /* NOTE: minix filenames are NULL terminated if < NAMELEN
4977c478bd9Sstevel@tonic-gate 	     else exact */
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate #ifdef DEBUG_MINIX
5007c478bd9Sstevel@tonic-gate 	  printf ("directory entry ino=%d\n", dp->inode);
5017c478bd9Sstevel@tonic-gate 	  if (dp->inode)
5027c478bd9Sstevel@tonic-gate 	    printf ("entry=%s\n", dp->name);
5037c478bd9Sstevel@tonic-gate #endif
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	  if (dp->inode)
5067c478bd9Sstevel@tonic-gate 	    {
5077c478bd9Sstevel@tonic-gate 	      int saved_c = dp->name[namelen];
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	      dp->name[namelen] = 0;
5107c478bd9Sstevel@tonic-gate 	      str_chk = substring (dirname, dp->name);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate # ifndef STAGE1_5
5137c478bd9Sstevel@tonic-gate 	      if (print_possibilities && ch != '/'
5147c478bd9Sstevel@tonic-gate 		  && (!*dirname || str_chk <= 0))
5157c478bd9Sstevel@tonic-gate 		{
5167c478bd9Sstevel@tonic-gate 		  if (print_possibilities > 0)
5177c478bd9Sstevel@tonic-gate 		    print_possibilities = -print_possibilities;
5187c478bd9Sstevel@tonic-gate 		  print_a_completion (dp->name);
5197c478bd9Sstevel@tonic-gate 		}
5207c478bd9Sstevel@tonic-gate # endif
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	      dp->name[namelen] = saved_c;
5237c478bd9Sstevel@tonic-gate 	    }
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	}
5267c478bd9Sstevel@tonic-gate       while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate       current_ino = dp->inode;
5297c478bd9Sstevel@tonic-gate       *(dirname = rest) = ch;
5307c478bd9Sstevel@tonic-gate     }
5317c478bd9Sstevel@tonic-gate   /* never get here */
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate #endif /* FSYS_MINIX */
535