xref: /illumos-gate/usr/src/grub/grub-0.97/stage2/fsys_ext2fs.c (revision 1b8adde7ba7d5e04395c141c5400dc2cffd7d809)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  *  GRUB  --  GRand Unified Bootloader
37c478bd9Sstevel@tonic-gate  *  Copyright (C) 1999, 2001, 2003  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 #ifdef FSYS_EXT2FS
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate #include "shared.h"
237c478bd9Sstevel@tonic-gate #include "filesys.h"
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate static int mapblock1, mapblock2;
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
287c478bd9Sstevel@tonic-gate #define DEV_BSIZE 512
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /* include/linux/fs.h */
317c478bd9Sstevel@tonic-gate #define BLOCK_SIZE 1024		/* initial block size for superblock read */
327c478bd9Sstevel@tonic-gate /* made up, defaults to 1 but can be passed via mount_opts */
337c478bd9Sstevel@tonic-gate #define WHICH_SUPER 1
347c478bd9Sstevel@tonic-gate /* kind of from fs/ext2/super.c */
357c478bd9Sstevel@tonic-gate #define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE)	/* = 2 */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /* include/asm-i386/types.h */
387c478bd9Sstevel@tonic-gate typedef __signed__ char __s8;
397c478bd9Sstevel@tonic-gate typedef unsigned char __u8;
407c478bd9Sstevel@tonic-gate typedef __signed__ short __s16;
417c478bd9Sstevel@tonic-gate typedef unsigned short __u16;
427c478bd9Sstevel@tonic-gate typedef __signed__ int __s32;
437c478bd9Sstevel@tonic-gate typedef unsigned int __u32;
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * Constants relative to the data blocks, from ext2_fs.h
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate #define EXT2_NDIR_BLOCKS                12
497c478bd9Sstevel@tonic-gate #define EXT2_IND_BLOCK                  EXT2_NDIR_BLOCKS
507c478bd9Sstevel@tonic-gate #define EXT2_DIND_BLOCK                 (EXT2_IND_BLOCK + 1)
517c478bd9Sstevel@tonic-gate #define EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)
527c478bd9Sstevel@tonic-gate #define EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /* include/linux/ext2_fs.h */
557c478bd9Sstevel@tonic-gate struct ext2_super_block
567c478bd9Sstevel@tonic-gate   {
577c478bd9Sstevel@tonic-gate     __u32 s_inodes_count;	/* Inodes count */
587c478bd9Sstevel@tonic-gate     __u32 s_blocks_count;	/* Blocks count */
597c478bd9Sstevel@tonic-gate     __u32 s_r_blocks_count;	/* Reserved blocks count */
607c478bd9Sstevel@tonic-gate     __u32 s_free_blocks_count;	/* Free blocks count */
617c478bd9Sstevel@tonic-gate     __u32 s_free_inodes_count;	/* Free inodes count */
627c478bd9Sstevel@tonic-gate     __u32 s_first_data_block;	/* First Data Block */
637c478bd9Sstevel@tonic-gate     __u32 s_log_block_size;	/* Block size */
647c478bd9Sstevel@tonic-gate     __s32 s_log_frag_size;	/* Fragment size */
657c478bd9Sstevel@tonic-gate     __u32 s_blocks_per_group;	/* # Blocks per group */
667c478bd9Sstevel@tonic-gate     __u32 s_frags_per_group;	/* # Fragments per group */
677c478bd9Sstevel@tonic-gate     __u32 s_inodes_per_group;	/* # Inodes per group */
687c478bd9Sstevel@tonic-gate     __u32 s_mtime;		/* Mount time */
697c478bd9Sstevel@tonic-gate     __u32 s_wtime;		/* Write time */
707c478bd9Sstevel@tonic-gate     __u16 s_mnt_count;		/* Mount count */
717c478bd9Sstevel@tonic-gate     __s16 s_max_mnt_count;	/* Maximal mount count */
727c478bd9Sstevel@tonic-gate     __u16 s_magic;		/* Magic signature */
737c478bd9Sstevel@tonic-gate     __u16 s_state;		/* File system state */
747c478bd9Sstevel@tonic-gate     __u16 s_errors;		/* Behaviour when detecting errors */
757c478bd9Sstevel@tonic-gate     __u16 s_pad;
767c478bd9Sstevel@tonic-gate     __u32 s_lastcheck;		/* time of last check */
777c478bd9Sstevel@tonic-gate     __u32 s_checkinterval;	/* max. time between checks */
787c478bd9Sstevel@tonic-gate     __u32 s_creator_os;		/* OS */
797c478bd9Sstevel@tonic-gate     __u32 s_rev_level;		/* Revision level */
807c478bd9Sstevel@tonic-gate     __u16 s_def_resuid;		/* Default uid for reserved blocks */
817c478bd9Sstevel@tonic-gate     __u16 s_def_resgid;		/* Default gid for reserved blocks */
82*1b8adde7SWilliam Kucharski    /*
83*1b8adde7SWilliam Kucharski     * These fields are for EXT2_DYNAMIC_REV superblocks only.
84*1b8adde7SWilliam Kucharski     *
85*1b8adde7SWilliam Kucharski     * Note: the difference between the compatible feature set and
86*1b8adde7SWilliam Kucharski     * the incompatible feature set is that if there is a bit set
87*1b8adde7SWilliam Kucharski     * in the incompatible feature set that the kernel doesn't
88*1b8adde7SWilliam Kucharski     * know about, it should refuse to mount the filesystem.
89*1b8adde7SWilliam Kucharski     *
90*1b8adde7SWilliam Kucharski     * e2fsck's requirements are more strict; if it doesn't know
91*1b8adde7SWilliam Kucharski     * about a feature in either the compatible or incompatible
92*1b8adde7SWilliam Kucharski     * feature set, it must abort and not try to meddle with
93*1b8adde7SWilliam Kucharski     * things it doesn't understand...
94*1b8adde7SWilliam Kucharski     */
95*1b8adde7SWilliam Kucharski    __u32 s_first_ino;		/* First non-reserved inode */
96*1b8adde7SWilliam Kucharski    __u16 s_inode_size;		/* size of inode structure */
97*1b8adde7SWilliam Kucharski    __u16 s_block_group_nr;	/* block group # of this superblock */
98*1b8adde7SWilliam Kucharski    __u32 s_feature_compat;	/* compatible feature set */
99*1b8adde7SWilliam Kucharski    __u32 s_feature_incompat;	/* incompatible feature set */
100*1b8adde7SWilliam Kucharski    __u32 s_feature_ro_compat;	/* readonly-compatible feature set */
101*1b8adde7SWilliam Kucharski    __u8  s_uuid[16];		/* 128-bit uuid for volume */
102*1b8adde7SWilliam Kucharski    char  s_volume_name[16];	/* volume name */
103*1b8adde7SWilliam Kucharski    char  s_last_mounted[64];	/* directory where last mounted */
104*1b8adde7SWilliam Kucharski    __u32 s_algorithm_usage_bitmap; /* For compression */
105*1b8adde7SWilliam Kucharski    /*
106*1b8adde7SWilliam Kucharski     * Performance hints.  Directory preallocation should only
107*1b8adde7SWilliam Kucharski     * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
108*1b8adde7SWilliam Kucharski     */
109*1b8adde7SWilliam Kucharski    __u8  s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/
110*1b8adde7SWilliam Kucharski    __u8  s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */
111*1b8adde7SWilliam Kucharski    __u16 s_reserved_gdt_blocks;/* Per group table for online growth */
112*1b8adde7SWilliam Kucharski    /*
113*1b8adde7SWilliam Kucharski     * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
114*1b8adde7SWilliam Kucharski     */
115*1b8adde7SWilliam Kucharski    __u8 s_journal_uuid[16];	/* uuid of journal superblock */
116*1b8adde7SWilliam Kucharski    __u32 s_journal_inum;	/* inode number of journal file */
117*1b8adde7SWilliam Kucharski    __u32 s_journal_dev;	/* device number of journal file */
118*1b8adde7SWilliam Kucharski    __u32 s_last_orphan;	/* start of list of inodes to delete */
119*1b8adde7SWilliam Kucharski    __u32 s_hash_seed[4];	/* HTREE hash seed */
120*1b8adde7SWilliam Kucharski    __u8  s_def_hash_version;	/* Default hash version to use */
121*1b8adde7SWilliam Kucharski    __u8  s_jnl_backup_type; 	/* Default type of journal backup */
122*1b8adde7SWilliam Kucharski    __u16 s_reserved_word_pad;
123*1b8adde7SWilliam Kucharski    __u32 s_default_mount_opts;
124*1b8adde7SWilliam Kucharski    __u32 s_first_meta_bg;	/* First metablock group */
125*1b8adde7SWilliam Kucharski    __u32 s_mkfs_time;		/* When the filesystem was created */
126*1b8adde7SWilliam Kucharski    __u32 s_jnl_blocks[17]; 	/* Backup of the journal inode */
127*1b8adde7SWilliam Kucharski    __u32 s_reserved[172];	/* Padding to the end of the block */
1287c478bd9Sstevel@tonic-gate   };
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate struct ext2_group_desc
1317c478bd9Sstevel@tonic-gate   {
1327c478bd9Sstevel@tonic-gate     __u32 bg_block_bitmap;	/* Blocks bitmap block */
1337c478bd9Sstevel@tonic-gate     __u32 bg_inode_bitmap;	/* Inodes bitmap block */
1347c478bd9Sstevel@tonic-gate     __u32 bg_inode_table;	/* Inodes table block */
1357c478bd9Sstevel@tonic-gate     __u16 bg_free_blocks_count;	/* Free blocks count */
1367c478bd9Sstevel@tonic-gate     __u16 bg_free_inodes_count;	/* Free inodes count */
1377c478bd9Sstevel@tonic-gate     __u16 bg_used_dirs_count;	/* Directories count */
1387c478bd9Sstevel@tonic-gate     __u16 bg_pad;
1397c478bd9Sstevel@tonic-gate     __u32 bg_reserved[3];
1407c478bd9Sstevel@tonic-gate   };
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate struct ext2_inode
1437c478bd9Sstevel@tonic-gate   {
1447c478bd9Sstevel@tonic-gate     __u16 i_mode;		/* File mode */
1457c478bd9Sstevel@tonic-gate     __u16 i_uid;		/* Owner Uid */
1467c478bd9Sstevel@tonic-gate     __u32 i_size;		/* 4: Size in bytes */
1477c478bd9Sstevel@tonic-gate     __u32 i_atime;		/* Access time */
1487c478bd9Sstevel@tonic-gate     __u32 i_ctime;		/* 12: Creation time */
1497c478bd9Sstevel@tonic-gate     __u32 i_mtime;		/* Modification time */
1507c478bd9Sstevel@tonic-gate     __u32 i_dtime;		/* 20: Deletion Time */
1517c478bd9Sstevel@tonic-gate     __u16 i_gid;		/* Group Id */
1527c478bd9Sstevel@tonic-gate     __u16 i_links_count;	/* 24: Links count */
1537c478bd9Sstevel@tonic-gate     __u32 i_blocks;		/* Blocks count */
1547c478bd9Sstevel@tonic-gate     __u32 i_flags;		/* 32: File flags */
1557c478bd9Sstevel@tonic-gate     union
1567c478bd9Sstevel@tonic-gate       {
1577c478bd9Sstevel@tonic-gate 	struct
1587c478bd9Sstevel@tonic-gate 	  {
1597c478bd9Sstevel@tonic-gate 	    __u32 l_i_reserved1;
1607c478bd9Sstevel@tonic-gate 	  }
1617c478bd9Sstevel@tonic-gate 	linux1;
1627c478bd9Sstevel@tonic-gate 	struct
1637c478bd9Sstevel@tonic-gate 	  {
1647c478bd9Sstevel@tonic-gate 	    __u32 h_i_translator;
1657c478bd9Sstevel@tonic-gate 	  }
1667c478bd9Sstevel@tonic-gate 	hurd1;
1677c478bd9Sstevel@tonic-gate 	struct
1687c478bd9Sstevel@tonic-gate 	  {
1697c478bd9Sstevel@tonic-gate 	    __u32 m_i_reserved1;
1707c478bd9Sstevel@tonic-gate 	  }
1717c478bd9Sstevel@tonic-gate 	masix1;
1727c478bd9Sstevel@tonic-gate       }
1737c478bd9Sstevel@tonic-gate     osd1;			/* OS dependent 1 */
1747c478bd9Sstevel@tonic-gate     __u32 i_block[EXT2_N_BLOCKS];	/* 40: Pointers to blocks */
1757c478bd9Sstevel@tonic-gate     __u32 i_version;		/* File version (for NFS) */
1767c478bd9Sstevel@tonic-gate     __u32 i_file_acl;		/* File ACL */
1777c478bd9Sstevel@tonic-gate     __u32 i_dir_acl;		/* Directory ACL */
1787c478bd9Sstevel@tonic-gate     __u32 i_faddr;		/* Fragment address */
1797c478bd9Sstevel@tonic-gate     union
1807c478bd9Sstevel@tonic-gate       {
1817c478bd9Sstevel@tonic-gate 	struct
1827c478bd9Sstevel@tonic-gate 	  {
1837c478bd9Sstevel@tonic-gate 	    __u8 l_i_frag;	/* Fragment number */
1847c478bd9Sstevel@tonic-gate 	    __u8 l_i_fsize;	/* Fragment size */
1857c478bd9Sstevel@tonic-gate 	    __u16 i_pad1;
1867c478bd9Sstevel@tonic-gate 	    __u32 l_i_reserved2[2];
1877c478bd9Sstevel@tonic-gate 	  }
1887c478bd9Sstevel@tonic-gate 	linux2;
1897c478bd9Sstevel@tonic-gate 	struct
1907c478bd9Sstevel@tonic-gate 	  {
1917c478bd9Sstevel@tonic-gate 	    __u8 h_i_frag;	/* Fragment number */
1927c478bd9Sstevel@tonic-gate 	    __u8 h_i_fsize;	/* Fragment size */
1937c478bd9Sstevel@tonic-gate 	    __u16 h_i_mode_high;
1947c478bd9Sstevel@tonic-gate 	    __u16 h_i_uid_high;
1957c478bd9Sstevel@tonic-gate 	    __u16 h_i_gid_high;
1967c478bd9Sstevel@tonic-gate 	    __u32 h_i_author;
1977c478bd9Sstevel@tonic-gate 	  }
1987c478bd9Sstevel@tonic-gate 	hurd2;
1997c478bd9Sstevel@tonic-gate 	struct
2007c478bd9Sstevel@tonic-gate 	  {
2017c478bd9Sstevel@tonic-gate 	    __u8 m_i_frag;	/* Fragment number */
2027c478bd9Sstevel@tonic-gate 	    __u8 m_i_fsize;	/* Fragment size */
2037c478bd9Sstevel@tonic-gate 	    __u16 m_pad1;
2047c478bd9Sstevel@tonic-gate 	    __u32 m_i_reserved2[2];
2057c478bd9Sstevel@tonic-gate 	  }
2067c478bd9Sstevel@tonic-gate 	masix2;
2077c478bd9Sstevel@tonic-gate       }
2087c478bd9Sstevel@tonic-gate     osd2;			/* OS dependent 2 */
2097c478bd9Sstevel@tonic-gate   };
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate /* linux/limits.h */
2127c478bd9Sstevel@tonic-gate #define NAME_MAX         255	/* # chars in a file name */
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate /* linux/posix_type.h */
2157c478bd9Sstevel@tonic-gate typedef long linux_off_t;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate /* linux/ext2fs.h */
2187c478bd9Sstevel@tonic-gate #define EXT2_NAME_LEN 255
2197c478bd9Sstevel@tonic-gate struct ext2_dir_entry
2207c478bd9Sstevel@tonic-gate   {
2217c478bd9Sstevel@tonic-gate     __u32 inode;		/* Inode number */
2227c478bd9Sstevel@tonic-gate     __u16 rec_len;		/* Directory entry length */
2237c478bd9Sstevel@tonic-gate     __u8 name_len;		/* Name length */
2247c478bd9Sstevel@tonic-gate     __u8 file_type;
2257c478bd9Sstevel@tonic-gate     char name[EXT2_NAME_LEN];	/* File name */
2267c478bd9Sstevel@tonic-gate   };
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate /* linux/ext2fs.h */
2297c478bd9Sstevel@tonic-gate /*
2307c478bd9Sstevel@tonic-gate  * EXT2_DIR_PAD defines the directory entries boundaries
2317c478bd9Sstevel@tonic-gate  *
2327c478bd9Sstevel@tonic-gate  * NOTE: It must be a multiple of 4
2337c478bd9Sstevel@tonic-gate  */
2347c478bd9Sstevel@tonic-gate #define EXT2_DIR_PAD                    4
2357c478bd9Sstevel@tonic-gate #define EXT2_DIR_ROUND                  (EXT2_DIR_PAD - 1)
2367c478bd9Sstevel@tonic-gate #define EXT2_DIR_REC_LEN(name_len)      (((name_len) + 8 + EXT2_DIR_ROUND) & \
2377c478bd9Sstevel@tonic-gate                                          ~EXT2_DIR_ROUND)
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate /* ext2/super.c */
2417c478bd9Sstevel@tonic-gate #define log2(n) ffz(~(n))
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate #define EXT2_SUPER_MAGIC      0xEF53	/* include/linux/ext2_fs.h */
2447c478bd9Sstevel@tonic-gate #define EXT2_ROOT_INO              2	/* include/linux/ext2_fs.h */
2457c478bd9Sstevel@tonic-gate #define PATH_MAX                1024	/* include/linux/limits.h */
2467c478bd9Sstevel@tonic-gate #define MAX_LINK_COUNT             5	/* number of symbolic links to follow */
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /* made up, these are pointers into FSYS_BUF */
2497c478bd9Sstevel@tonic-gate /* read once, always stays there: */
2507c478bd9Sstevel@tonic-gate #define SUPERBLOCK \
2517c478bd9Sstevel@tonic-gate     ((struct ext2_super_block *)(FSYS_BUF))
2527c478bd9Sstevel@tonic-gate #define GROUP_DESC \
2537c478bd9Sstevel@tonic-gate     ((struct ext2_group_desc *) \
2547c478bd9Sstevel@tonic-gate      ((int)SUPERBLOCK + sizeof(struct ext2_super_block)))
2557c478bd9Sstevel@tonic-gate #define INODE \
2567c478bd9Sstevel@tonic-gate     ((struct ext2_inode *)((int)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK)))
2577c478bd9Sstevel@tonic-gate #define DATABLOCK1 \
2587c478bd9Sstevel@tonic-gate     ((int)((int)INODE + sizeof(struct ext2_inode)))
2597c478bd9Sstevel@tonic-gate #define DATABLOCK2 \
2607c478bd9Sstevel@tonic-gate     ((int)((int)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK)))
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate /* linux/ext2_fs.h */
2637c478bd9Sstevel@tonic-gate #define EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
2647c478bd9Sstevel@tonic-gate #define EXT2_ADDR_PER_BLOCK_BITS(s)		(log2(EXT2_ADDR_PER_BLOCK(s)))
2657c478bd9Sstevel@tonic-gate 
266*1b8adde7SWilliam Kucharski #define EXT2_INODE_SIZE(s)		(SUPERBLOCK->s_inode_size)
267*1b8adde7SWilliam Kucharski #define EXT2_INODES_PER_BLOCK(s)	(EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
268*1b8adde7SWilliam Kucharski 
2697c478bd9Sstevel@tonic-gate /* linux/ext2_fs.h */
2707c478bd9Sstevel@tonic-gate #define EXT2_BLOCK_SIZE_BITS(s)        ((s)->s_log_block_size + 10)
2717c478bd9Sstevel@tonic-gate /* kind of from ext2/super.c */
2727c478bd9Sstevel@tonic-gate #define EXT2_BLOCK_SIZE(s)	(1 << EXT2_BLOCK_SIZE_BITS(s))
2737c478bd9Sstevel@tonic-gate /* linux/ext2fs.h */
2747c478bd9Sstevel@tonic-gate #define EXT2_DESC_PER_BLOCK(s) \
2757c478bd9Sstevel@tonic-gate      (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
2767c478bd9Sstevel@tonic-gate /* linux/stat.h */
2777c478bd9Sstevel@tonic-gate #define S_IFMT  00170000
2787c478bd9Sstevel@tonic-gate #define S_IFLNK  0120000
2797c478bd9Sstevel@tonic-gate #define S_IFREG  0100000
2807c478bd9Sstevel@tonic-gate #define S_IFDIR  0040000
2817c478bd9Sstevel@tonic-gate #define S_ISLNK(m)	(((m) & S_IFMT) == S_IFLNK)
2827c478bd9Sstevel@tonic-gate #define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
2837c478bd9Sstevel@tonic-gate #define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate /* include/asm-i386/bitops.h */
2867c478bd9Sstevel@tonic-gate /*
2877c478bd9Sstevel@tonic-gate  * ffz = Find First Zero in word. Undefined if no zero exists,
2887c478bd9Sstevel@tonic-gate  * so code should check against ~0UL first..
2897c478bd9Sstevel@tonic-gate  */
2907c478bd9Sstevel@tonic-gate static __inline__ unsigned long
2917c478bd9Sstevel@tonic-gate ffz (unsigned long word)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate   __asm__ ("bsfl %1,%0"
2947c478bd9Sstevel@tonic-gate :	   "=r" (word)
2957c478bd9Sstevel@tonic-gate :	   "r" (~word));
2967c478bd9Sstevel@tonic-gate   return word;
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate /* check filesystem types and read superblock into memory buffer */
3007c478bd9Sstevel@tonic-gate int
3017c478bd9Sstevel@tonic-gate ext2fs_mount (void)
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate   int retval = 1;
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate   if ((((current_drive & 0x80) || (current_slice != 0))
3067c478bd9Sstevel@tonic-gate        && (current_slice != PC_SLICE_TYPE_EXT2FS)
3077c478bd9Sstevel@tonic-gate        && (current_slice != PC_SLICE_TYPE_LINUX_RAID)
3087c478bd9Sstevel@tonic-gate        && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS))
3097c478bd9Sstevel@tonic-gate        && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER)))
3107c478bd9Sstevel@tonic-gate       || part_length < (SBLOCK + (sizeof (struct ext2_super_block) / DEV_BSIZE))
3117c478bd9Sstevel@tonic-gate       || !devread (SBLOCK, 0, sizeof (struct ext2_super_block),
3127c478bd9Sstevel@tonic-gate 		   (char *) SUPERBLOCK)
3137c478bd9Sstevel@tonic-gate       || SUPERBLOCK->s_magic != EXT2_SUPER_MAGIC)
3147c478bd9Sstevel@tonic-gate       retval = 0;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate   return retval;
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate /* Takes a file system block number and reads it into BUFFER. */
3207c478bd9Sstevel@tonic-gate static int
3217c478bd9Sstevel@tonic-gate ext2_rdfsb (int fsblock, int buffer)
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
3247c478bd9Sstevel@tonic-gate   printf ("fsblock %d buffer %d\n", fsblock, buffer);
3257c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
3267c478bd9Sstevel@tonic-gate   return devread (fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0,
3277c478bd9Sstevel@tonic-gate 		  EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate /* from
3317c478bd9Sstevel@tonic-gate   ext2/inode.c:ext2_bmap()
3327c478bd9Sstevel@tonic-gate */
3337c478bd9Sstevel@tonic-gate /* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
3347c478bd9Sstevel@tonic-gate    a physical block (the location in the file system) via an inode. */
3357c478bd9Sstevel@tonic-gate static int
3367c478bd9Sstevel@tonic-gate ext2fs_block_map (int logical_block)
3377c478bd9Sstevel@tonic-gate {
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
3407c478bd9Sstevel@tonic-gate   unsigned char *i;
3417c478bd9Sstevel@tonic-gate   for (i = (unsigned char *) INODE;
3427c478bd9Sstevel@tonic-gate        i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
3437c478bd9Sstevel@tonic-gate        i++)
3447c478bd9Sstevel@tonic-gate     {
3457c478bd9Sstevel@tonic-gate       printf ("%c", "0123456789abcdef"[*i >> 4]);
3467c478bd9Sstevel@tonic-gate       printf ("%c", "0123456789abcdef"[*i % 16]);
3477c478bd9Sstevel@tonic-gate       if (!((i + 1 - (unsigned char *) INODE) % 16))
3487c478bd9Sstevel@tonic-gate 	{
3497c478bd9Sstevel@tonic-gate 	  printf ("\n");
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate       else
3527c478bd9Sstevel@tonic-gate 	{
3537c478bd9Sstevel@tonic-gate 	  printf (" ");
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate     }
3567c478bd9Sstevel@tonic-gate   printf ("logical block %d\n", logical_block);
3577c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate   /* if it is directly pointed to by the inode, return that physical addr */
3607c478bd9Sstevel@tonic-gate   if (logical_block < EXT2_NDIR_BLOCKS)
3617c478bd9Sstevel@tonic-gate     {
3627c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
3637c478bd9Sstevel@tonic-gate       printf ("returning %d\n", (unsigned char *) (INODE->i_block[logical_block]));
3647c478bd9Sstevel@tonic-gate       printf ("returning %d\n", INODE->i_block[logical_block]);
3657c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
3667c478bd9Sstevel@tonic-gate       return INODE->i_block[logical_block];
3677c478bd9Sstevel@tonic-gate     }
3687c478bd9Sstevel@tonic-gate   /* else */
3697c478bd9Sstevel@tonic-gate   logical_block -= EXT2_NDIR_BLOCKS;
3707c478bd9Sstevel@tonic-gate   /* try the indirect block */
3717c478bd9Sstevel@tonic-gate   if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
3727c478bd9Sstevel@tonic-gate     {
3737c478bd9Sstevel@tonic-gate       if (mapblock1 != 1
3747c478bd9Sstevel@tonic-gate 	  && !ext2_rdfsb (INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1))
3757c478bd9Sstevel@tonic-gate 	{
3767c478bd9Sstevel@tonic-gate 	  errnum = ERR_FSYS_CORRUPT;
3777c478bd9Sstevel@tonic-gate 	  return -1;
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate       mapblock1 = 1;
3807c478bd9Sstevel@tonic-gate       return ((__u32 *) DATABLOCK1)[logical_block];
3817c478bd9Sstevel@tonic-gate     }
3827c478bd9Sstevel@tonic-gate   /* else */
3837c478bd9Sstevel@tonic-gate   logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
3847c478bd9Sstevel@tonic-gate   /* now try the double indirect block */
3857c478bd9Sstevel@tonic-gate   if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
3867c478bd9Sstevel@tonic-gate     {
3877c478bd9Sstevel@tonic-gate       int bnum;
3887c478bd9Sstevel@tonic-gate       if (mapblock1 != 2
3897c478bd9Sstevel@tonic-gate 	  && !ext2_rdfsb (INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1))
3907c478bd9Sstevel@tonic-gate 	{
3917c478bd9Sstevel@tonic-gate 	  errnum = ERR_FSYS_CORRUPT;
3927c478bd9Sstevel@tonic-gate 	  return -1;
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate       mapblock1 = 2;
3957c478bd9Sstevel@tonic-gate       if ((bnum = (((__u32 *) DATABLOCK1)
3967c478bd9Sstevel@tonic-gate 		   [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
3977c478bd9Sstevel@tonic-gate 	  != mapblock2
3987c478bd9Sstevel@tonic-gate 	  && !ext2_rdfsb (bnum, DATABLOCK2))
3997c478bd9Sstevel@tonic-gate 	{
4007c478bd9Sstevel@tonic-gate 	  errnum = ERR_FSYS_CORRUPT;
4017c478bd9Sstevel@tonic-gate 	  return -1;
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate       mapblock2 = bnum;
4047c478bd9Sstevel@tonic-gate       return ((__u32 *) DATABLOCK2)
4057c478bd9Sstevel@tonic-gate 	[logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
4067c478bd9Sstevel@tonic-gate     }
4077c478bd9Sstevel@tonic-gate   /* else */
4087c478bd9Sstevel@tonic-gate   mapblock2 = -1;
4097c478bd9Sstevel@tonic-gate   logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
4107c478bd9Sstevel@tonic-gate   if (mapblock1 != 3
4117c478bd9Sstevel@tonic-gate       && !ext2_rdfsb (INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1))
4127c478bd9Sstevel@tonic-gate     {
4137c478bd9Sstevel@tonic-gate       errnum = ERR_FSYS_CORRUPT;
4147c478bd9Sstevel@tonic-gate       return -1;
4157c478bd9Sstevel@tonic-gate     }
4167c478bd9Sstevel@tonic-gate   mapblock1 = 3;
4177c478bd9Sstevel@tonic-gate   if (!ext2_rdfsb (((__u32 *) DATABLOCK1)
4187c478bd9Sstevel@tonic-gate 		   [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
4197c478bd9Sstevel@tonic-gate 				      * 2)],
4207c478bd9Sstevel@tonic-gate 		   DATABLOCK2))
4217c478bd9Sstevel@tonic-gate     {
4227c478bd9Sstevel@tonic-gate       errnum = ERR_FSYS_CORRUPT;
4237c478bd9Sstevel@tonic-gate       return -1;
4247c478bd9Sstevel@tonic-gate     }
4257c478bd9Sstevel@tonic-gate   if (!ext2_rdfsb (((__u32 *) DATABLOCK2)
4267c478bd9Sstevel@tonic-gate 		   [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
4277c478bd9Sstevel@tonic-gate 		    & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)],
4287c478bd9Sstevel@tonic-gate 		   DATABLOCK2))
4297c478bd9Sstevel@tonic-gate     {
4307c478bd9Sstevel@tonic-gate       errnum = ERR_FSYS_CORRUPT;
4317c478bd9Sstevel@tonic-gate       return -1;
4327c478bd9Sstevel@tonic-gate     }
4337c478bd9Sstevel@tonic-gate   return ((__u32 *) DATABLOCK2)
4347c478bd9Sstevel@tonic-gate     [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate /* preconditions: all preconds of ext2fs_block_map */
4387c478bd9Sstevel@tonic-gate int
4397c478bd9Sstevel@tonic-gate ext2fs_read (char *buf, int len)
4407c478bd9Sstevel@tonic-gate {
4417c478bd9Sstevel@tonic-gate   int logical_block;
4427c478bd9Sstevel@tonic-gate   int offset;
4437c478bd9Sstevel@tonic-gate   int map;
4447c478bd9Sstevel@tonic-gate   int ret = 0;
4457c478bd9Sstevel@tonic-gate   int size = 0;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
4487c478bd9Sstevel@tonic-gate   static char hexdigit[] = "0123456789abcdef";
4497c478bd9Sstevel@tonic-gate   unsigned char *i;
4507c478bd9Sstevel@tonic-gate   for (i = (unsigned char *) INODE;
4517c478bd9Sstevel@tonic-gate        i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
4527c478bd9Sstevel@tonic-gate        i++)
4537c478bd9Sstevel@tonic-gate     {
4547c478bd9Sstevel@tonic-gate       printf ("%c", hexdigit[*i >> 4]);
4557c478bd9Sstevel@tonic-gate       printf ("%c", hexdigit[*i % 16]);
4567c478bd9Sstevel@tonic-gate       if (!((i + 1 - (unsigned char *) INODE) % 16))
4577c478bd9Sstevel@tonic-gate 	{
4587c478bd9Sstevel@tonic-gate 	  printf ("\n");
4597c478bd9Sstevel@tonic-gate 	}
4607c478bd9Sstevel@tonic-gate       else
4617c478bd9Sstevel@tonic-gate 	{
4627c478bd9Sstevel@tonic-gate 	  printf (" ");
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate     }
4657c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
4667c478bd9Sstevel@tonic-gate   while (len > 0)
4677c478bd9Sstevel@tonic-gate     {
4687c478bd9Sstevel@tonic-gate       /* find the (logical) block component of our location */
4697c478bd9Sstevel@tonic-gate       logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
4707c478bd9Sstevel@tonic-gate       offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
4717c478bd9Sstevel@tonic-gate       map = ext2fs_block_map (logical_block);
4727c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
4737c478bd9Sstevel@tonic-gate       printf ("map=%d\n", map);
4747c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
4757c478bd9Sstevel@tonic-gate       if (map < 0)
4767c478bd9Sstevel@tonic-gate 	break;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate       size = EXT2_BLOCK_SIZE (SUPERBLOCK);
4797c478bd9Sstevel@tonic-gate       size -= offset;
4807c478bd9Sstevel@tonic-gate       if (size > len)
4817c478bd9Sstevel@tonic-gate 	size = len;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate       if (map == 0) {
4847c478bd9Sstevel@tonic-gate         memset ((char *) buf, 0, size);
4857c478bd9Sstevel@tonic-gate       } else {
4867c478bd9Sstevel@tonic-gate         disk_read_func = disk_read_hook;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate         devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE),
4897c478bd9Sstevel@tonic-gate 	         offset, size, buf);
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate         disk_read_func = NULL;
4927c478bd9Sstevel@tonic-gate       }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate       buf += size;
4957c478bd9Sstevel@tonic-gate       len -= size;
4967c478bd9Sstevel@tonic-gate       filepos += size;
4977c478bd9Sstevel@tonic-gate       ret += size;
4987c478bd9Sstevel@tonic-gate     }
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate   if (errnum)
5017c478bd9Sstevel@tonic-gate     ret = 0;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate   return ret;
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate /* Based on:
5087c478bd9Sstevel@tonic-gate    def_blk_fops points to
5097c478bd9Sstevel@tonic-gate    blkdev_open, which calls (I think):
5107c478bd9Sstevel@tonic-gate    sys_open()
5117c478bd9Sstevel@tonic-gate    do_open()
5127c478bd9Sstevel@tonic-gate    open_namei()
5137c478bd9Sstevel@tonic-gate    dir_namei() which accesses current->fs->root
5147c478bd9Sstevel@tonic-gate      fs->root was set during original mount:
5157c478bd9Sstevel@tonic-gate      (something)... which calls (I think):
5167c478bd9Sstevel@tonic-gate      ext2_read_super()
5177c478bd9Sstevel@tonic-gate      iget()
5187c478bd9Sstevel@tonic-gate      __iget()
5197c478bd9Sstevel@tonic-gate      read_inode()
5207c478bd9Sstevel@tonic-gate      ext2_read_inode()
5217c478bd9Sstevel@tonic-gate        uses desc_per_block_bits, which is set in ext2_read_super()
5227c478bd9Sstevel@tonic-gate        also uses group descriptors loaded during ext2_read_super()
5237c478bd9Sstevel@tonic-gate    lookup()
5247c478bd9Sstevel@tonic-gate    ext2_lookup()
5257c478bd9Sstevel@tonic-gate    ext2_find_entry()
5267c478bd9Sstevel@tonic-gate    ext2_getblk()
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate */
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate static inline
5317c478bd9Sstevel@tonic-gate int ext2_is_fast_symlink (void)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate   int ea_blocks;
5347c478bd9Sstevel@tonic-gate   ea_blocks = INODE->i_file_acl ? EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE : 0;
5357c478bd9Sstevel@tonic-gate   return INODE->i_blocks == ea_blocks;
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate /* preconditions: ext2fs_mount already executed, therefore supblk in buffer
5397c478bd9Sstevel@tonic-gate  *   known as SUPERBLOCK
5407c478bd9Sstevel@tonic-gate  * returns: 0 if error, nonzero iff we were able to find the file successfully
5417c478bd9Sstevel@tonic-gate  * postconditions: on a nonzero return, buffer known as INODE contains the
5427c478bd9Sstevel@tonic-gate  *   inode of the file we were trying to look up
5437c478bd9Sstevel@tonic-gate  * side effects: messes up GROUP_DESC buffer area
5447c478bd9Sstevel@tonic-gate  */
5457c478bd9Sstevel@tonic-gate int
5467c478bd9Sstevel@tonic-gate ext2fs_dir (char *dirname)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate   int current_ino = EXT2_ROOT_INO;	/* start at the root */
5497c478bd9Sstevel@tonic-gate   int updir_ino = current_ino;	/* the parent of the current directory */
5507c478bd9Sstevel@tonic-gate   int group_id;			/* which group the inode is in */
5517c478bd9Sstevel@tonic-gate   int group_desc;		/* fs pointer to that group */
5527c478bd9Sstevel@tonic-gate   int desc;			/* index within that group */
5537c478bd9Sstevel@tonic-gate   int ino_blk;			/* fs pointer of the inode's information */
5547c478bd9Sstevel@tonic-gate   int str_chk = 0;		/* used to hold the results of a string compare */
5557c478bd9Sstevel@tonic-gate   struct ext2_group_desc *gdp;
5567c478bd9Sstevel@tonic-gate   struct ext2_inode *raw_inode;	/* inode info corresponding to current_ino */
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate   char linkbuf[PATH_MAX];	/* buffer for following symbolic links */
5597c478bd9Sstevel@tonic-gate   int link_count = 0;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate   char *rest;
5627c478bd9Sstevel@tonic-gate   char ch;			/* temp char holder */
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate   int off;			/* offset within block of directory entry (off mod blocksize) */
5657c478bd9Sstevel@tonic-gate   int loc;			/* location within a directory */
5667c478bd9Sstevel@tonic-gate   int blk;			/* which data blk within dir entry (off div blocksize) */
5677c478bd9Sstevel@tonic-gate   long map;			/* fs pointer of a particular block from dir entry */
5687c478bd9Sstevel@tonic-gate   struct ext2_dir_entry *dp;	/* pointer to directory entry */
5697c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
5707c478bd9Sstevel@tonic-gate   unsigned char *i;
5717c478bd9Sstevel@tonic-gate #endif	/* E2DEBUG */
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate   /* loop invariants:
5747c478bd9Sstevel@tonic-gate      current_ino = inode to lookup
5757c478bd9Sstevel@tonic-gate      dirname = pointer to filename component we are cur looking up within
5767c478bd9Sstevel@tonic-gate      the directory known pointed to by current_ino (if any)
5777c478bd9Sstevel@tonic-gate    */
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate   while (1)
5807c478bd9Sstevel@tonic-gate     {
5817c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
5827c478bd9Sstevel@tonic-gate       printf ("inode %d\n", current_ino);
5837c478bd9Sstevel@tonic-gate       printf ("dirname=%s\n", dirname);
5847c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate       /* look up an inode */
5877c478bd9Sstevel@tonic-gate       group_id = (current_ino - 1) / (SUPERBLOCK->s_inodes_per_group);
5887c478bd9Sstevel@tonic-gate       group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK));
5897c478bd9Sstevel@tonic-gate       desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1);
5907c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
5917c478bd9Sstevel@tonic-gate       printf ("ipg=%d, dpb=%d\n", SUPERBLOCK->s_inodes_per_group,
5927c478bd9Sstevel@tonic-gate 	      EXT2_DESC_PER_BLOCK (SUPERBLOCK));
5937c478bd9Sstevel@tonic-gate       printf ("group_id=%d group_desc=%d desc=%d\n", group_id, group_desc, desc);
5947c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
5957c478bd9Sstevel@tonic-gate       if (!ext2_rdfsb (
5967c478bd9Sstevel@tonic-gate 			(WHICH_SUPER + group_desc + SUPERBLOCK->s_first_data_block),
5977c478bd9Sstevel@tonic-gate 			(int) GROUP_DESC))
5987c478bd9Sstevel@tonic-gate 	{
5997c478bd9Sstevel@tonic-gate 	  return 0;
6007c478bd9Sstevel@tonic-gate 	}
6017c478bd9Sstevel@tonic-gate       gdp = GROUP_DESC;
6027c478bd9Sstevel@tonic-gate       ino_blk = gdp[desc].bg_inode_table +
6037c478bd9Sstevel@tonic-gate 	(((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group))
604*1b8adde7SWilliam Kucharski 	 >> log2 (EXT2_INODES_PER_BLOCK (SUPERBLOCK)));
6057c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
6067c478bd9Sstevel@tonic-gate       printf ("inode table fsblock=%d\n", ino_blk);
6077c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
6087c478bd9Sstevel@tonic-gate       if (!ext2_rdfsb (ino_blk, (int) INODE))
6097c478bd9Sstevel@tonic-gate 	{
6107c478bd9Sstevel@tonic-gate 	  return 0;
6117c478bd9Sstevel@tonic-gate 	}
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate       /* reset indirect blocks! */
6147c478bd9Sstevel@tonic-gate       mapblock2 = mapblock1 = -1;
6157c478bd9Sstevel@tonic-gate 
616*1b8adde7SWilliam Kucharski       raw_inode = (struct ext2_inode *)((char *)INODE +
617*1b8adde7SWilliam Kucharski 	((current_ino - 1) & (EXT2_INODES_PER_BLOCK (SUPERBLOCK) - 1)) *
618*1b8adde7SWilliam Kucharski 	EXT2_INODE_SIZE (SUPERBLOCK));
619*1b8adde7SWilliam Kucharski 
6207c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
6217c478bd9Sstevel@tonic-gate       printf ("ipb=%d, sizeof(inode)=%d\n",
622*1b8adde7SWilliam Kucharski 	      EXT2_INODES_PER_BLOCK (SUPERBLOCK), EXT2_INODE_SIZE (SUPERBLOCK));
6237c478bd9Sstevel@tonic-gate       printf ("inode=%x, raw_inode=%x\n", INODE, raw_inode);
6247c478bd9Sstevel@tonic-gate       printf ("offset into inode table block=%d\n", (int) raw_inode - (int) INODE);
6257c478bd9Sstevel@tonic-gate       for (i = (unsigned char *) INODE; i <= (unsigned char *) raw_inode;
6267c478bd9Sstevel@tonic-gate 	   i++)
6277c478bd9Sstevel@tonic-gate 	{
6287c478bd9Sstevel@tonic-gate 	  printf ("%c", "0123456789abcdef"[*i >> 4]);
6297c478bd9Sstevel@tonic-gate 	  printf ("%c", "0123456789abcdef"[*i % 16]);
6307c478bd9Sstevel@tonic-gate 	  if (!((i + 1 - (unsigned char *) INODE) % 16))
6317c478bd9Sstevel@tonic-gate 	    {
6327c478bd9Sstevel@tonic-gate 	      printf ("\n");
6337c478bd9Sstevel@tonic-gate 	    }
6347c478bd9Sstevel@tonic-gate 	  else
6357c478bd9Sstevel@tonic-gate 	    {
6367c478bd9Sstevel@tonic-gate 	      printf (" ");
6377c478bd9Sstevel@tonic-gate 	    }
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate       printf ("first word=%x\n", *((int *) raw_inode));
6407c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate       /* copy inode to fixed location */
6437c478bd9Sstevel@tonic-gate       memmove ((void *) INODE, (void *) raw_inode, sizeof (struct ext2_inode));
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
6467c478bd9Sstevel@tonic-gate       printf ("first word=%x\n", *((int *) INODE));
6477c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate       /* If we've got a symbolic link, then chase it. */
6507c478bd9Sstevel@tonic-gate       if (S_ISLNK (INODE->i_mode))
6517c478bd9Sstevel@tonic-gate 	{
6527c478bd9Sstevel@tonic-gate 	  int len;
6537c478bd9Sstevel@tonic-gate 	  if (++link_count > MAX_LINK_COUNT)
6547c478bd9Sstevel@tonic-gate 	    {
6557c478bd9Sstevel@tonic-gate 	      errnum = ERR_SYMLINK_LOOP;
6567c478bd9Sstevel@tonic-gate 	      return 0;
6577c478bd9Sstevel@tonic-gate 	    }
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	  /* Find out how long our remaining name is. */
6607c478bd9Sstevel@tonic-gate 	  len = 0;
6617c478bd9Sstevel@tonic-gate 	  while (dirname[len] && !isspace (dirname[len]))
6627c478bd9Sstevel@tonic-gate 	    len++;
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	  /* Get the symlink size. */
6657c478bd9Sstevel@tonic-gate 	  filemax = (INODE->i_size);
6667c478bd9Sstevel@tonic-gate 	  if (filemax + len > sizeof (linkbuf) - 2)
6677c478bd9Sstevel@tonic-gate 	    {
6687c478bd9Sstevel@tonic-gate 	      errnum = ERR_FILELENGTH;
6697c478bd9Sstevel@tonic-gate 	      return 0;
6707c478bd9Sstevel@tonic-gate 	    }
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	  if (len)
6737c478bd9Sstevel@tonic-gate 	    {
6747c478bd9Sstevel@tonic-gate 	      /* Copy the remaining name to the end of the symlink data.
6757c478bd9Sstevel@tonic-gate 	         Note that DIRNAME and LINKBUF may overlap! */
6767c478bd9Sstevel@tonic-gate 	      memmove (linkbuf + filemax, dirname, len);
6777c478bd9Sstevel@tonic-gate 	    }
6787c478bd9Sstevel@tonic-gate 	  linkbuf[filemax + len] = '\0';
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	  /* Read the symlink data. */
6817c478bd9Sstevel@tonic-gate 	  if (! ext2_is_fast_symlink ())
6827c478bd9Sstevel@tonic-gate 	    {
6837c478bd9Sstevel@tonic-gate 	      /* Read the necessary blocks, and reset the file pointer. */
6847c478bd9Sstevel@tonic-gate 	      len = grub_read (linkbuf, filemax);
6857c478bd9Sstevel@tonic-gate 	      filepos = 0;
6867c478bd9Sstevel@tonic-gate 	      if (!len)
6877c478bd9Sstevel@tonic-gate 		return 0;
6887c478bd9Sstevel@tonic-gate 	    }
6897c478bd9Sstevel@tonic-gate 	  else
6907c478bd9Sstevel@tonic-gate 	    {
6917c478bd9Sstevel@tonic-gate 	      /* Copy the data directly from the inode. */
6927c478bd9Sstevel@tonic-gate 	      len = filemax;
6937c478bd9Sstevel@tonic-gate 	      memmove (linkbuf, (char *) INODE->i_block, len);
6947c478bd9Sstevel@tonic-gate 	    }
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
6977c478bd9Sstevel@tonic-gate 	  printf ("symlink=%s\n", linkbuf);
6987c478bd9Sstevel@tonic-gate #endif
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	  dirname = linkbuf;
7017c478bd9Sstevel@tonic-gate 	  if (*dirname == '/')
7027c478bd9Sstevel@tonic-gate 	    {
7037c478bd9Sstevel@tonic-gate 	      /* It's an absolute link, so look it up in root. */
7047c478bd9Sstevel@tonic-gate 	      current_ino = EXT2_ROOT_INO;
7057c478bd9Sstevel@tonic-gate 	      updir_ino = current_ino;
7067c478bd9Sstevel@tonic-gate 	    }
7077c478bd9Sstevel@tonic-gate 	  else
7087c478bd9Sstevel@tonic-gate 	    {
7097c478bd9Sstevel@tonic-gate 	      /* Relative, so look it up in our parent directory. */
7107c478bd9Sstevel@tonic-gate 	      current_ino = updir_ino;
7117c478bd9Sstevel@tonic-gate 	    }
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	  /* Try again using the new name. */
7147c478bd9Sstevel@tonic-gate 	  continue;
7157c478bd9Sstevel@tonic-gate 	}
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate       /* if end of filename, INODE points to the file's inode */
7187c478bd9Sstevel@tonic-gate       if (!*dirname || isspace (*dirname))
7197c478bd9Sstevel@tonic-gate 	{
7207c478bd9Sstevel@tonic-gate 	  if (!S_ISREG (INODE->i_mode))
7217c478bd9Sstevel@tonic-gate 	    {
7227c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_FILETYPE;
7237c478bd9Sstevel@tonic-gate 	      return 0;
7247c478bd9Sstevel@tonic-gate 	    }
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	  filemax = (INODE->i_size);
7277c478bd9Sstevel@tonic-gate 	  return 1;
7287c478bd9Sstevel@tonic-gate 	}
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate       /* else we have to traverse a directory */
7317c478bd9Sstevel@tonic-gate       updir_ino = current_ino;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate       /* skip over slashes */
7347c478bd9Sstevel@tonic-gate       while (*dirname == '/')
7357c478bd9Sstevel@tonic-gate 	dirname++;
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate       /* if this isn't a directory of sufficient size to hold our file, abort */
7387c478bd9Sstevel@tonic-gate       if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode))
7397c478bd9Sstevel@tonic-gate 	{
7407c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_FILETYPE;
7417c478bd9Sstevel@tonic-gate 	  return 0;
7427c478bd9Sstevel@tonic-gate 	}
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate       /* skip to next slash or end of filename (space) */
7457c478bd9Sstevel@tonic-gate       for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
7467c478bd9Sstevel@tonic-gate 	   rest++);
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate       /* look through this directory and find the next filename component */
7497c478bd9Sstevel@tonic-gate       /* invariant: rest points to slash after the next filename component */
7507c478bd9Sstevel@tonic-gate       *rest = 0;
7517c478bd9Sstevel@tonic-gate       loc = 0;
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate       do
7547c478bd9Sstevel@tonic-gate 	{
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
7577c478bd9Sstevel@tonic-gate 	  printf ("dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc);
7587c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	  /* if our location/byte offset into the directory exceeds the size,
7617c478bd9Sstevel@tonic-gate 	     give up */
7627c478bd9Sstevel@tonic-gate 	  if (loc >= INODE->i_size)
7637c478bd9Sstevel@tonic-gate 	    {
7647c478bd9Sstevel@tonic-gate 	      if (print_possibilities < 0)
7657c478bd9Sstevel@tonic-gate 		{
7667c478bd9Sstevel@tonic-gate # if 0
7677c478bd9Sstevel@tonic-gate 		  putchar ('\n');
7687c478bd9Sstevel@tonic-gate # endif
7697c478bd9Sstevel@tonic-gate 		}
7707c478bd9Sstevel@tonic-gate 	      else
7717c478bd9Sstevel@tonic-gate 		{
7727c478bd9Sstevel@tonic-gate 		  errnum = ERR_FILE_NOT_FOUND;
7737c478bd9Sstevel@tonic-gate 		  *rest = ch;
7747c478bd9Sstevel@tonic-gate 		}
7757c478bd9Sstevel@tonic-gate 	      return (print_possibilities < 0);
7767c478bd9Sstevel@tonic-gate 	    }
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	  /* else, find the (logical) block component of our location */
7797c478bd9Sstevel@tonic-gate 	  blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	  /* we know which logical block of the directory entry we are looking
7827c478bd9Sstevel@tonic-gate 	     for, now we have to translate that to the physical (fs) block on
7837c478bd9Sstevel@tonic-gate 	     the disk */
7847c478bd9Sstevel@tonic-gate 	  map = ext2fs_block_map (blk);
7857c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
7867c478bd9Sstevel@tonic-gate 	  printf ("fs block=%d\n", map);
7877c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
7887c478bd9Sstevel@tonic-gate 	  mapblock2 = -1;
7897c478bd9Sstevel@tonic-gate 	  if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2))
7907c478bd9Sstevel@tonic-gate 	    {
7917c478bd9Sstevel@tonic-gate 	      errnum = ERR_FSYS_CORRUPT;
7927c478bd9Sstevel@tonic-gate 	      *rest = ch;
7937c478bd9Sstevel@tonic-gate 	      return 0;
7947c478bd9Sstevel@tonic-gate 	    }
7957c478bd9Sstevel@tonic-gate 	  off = loc & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
7967c478bd9Sstevel@tonic-gate 	  dp = (struct ext2_dir_entry *) (DATABLOCK2 + off);
7977c478bd9Sstevel@tonic-gate 	  /* advance loc prematurely to next on-disk directory entry  */
7987c478bd9Sstevel@tonic-gate 	  loc += dp->rec_len;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	  /* NOTE: ext2fs filenames are NOT null-terminated */
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate #ifdef E2DEBUG
8037c478bd9Sstevel@tonic-gate 	  printf ("directory entry ino=%d\n", dp->inode);
8047c478bd9Sstevel@tonic-gate 	  if (dp->inode)
8057c478bd9Sstevel@tonic-gate 	    printf ("entry=%s\n", dp->name);
8067c478bd9Sstevel@tonic-gate #endif /* E2DEBUG */
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	  if (dp->inode)
8097c478bd9Sstevel@tonic-gate 	    {
8107c478bd9Sstevel@tonic-gate 	      int saved_c = dp->name[dp->name_len];
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	      dp->name[dp->name_len] = 0;
8137c478bd9Sstevel@tonic-gate 	      str_chk = substring (dirname, dp->name);
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate # ifndef STAGE1_5
8167c478bd9Sstevel@tonic-gate 	      if (print_possibilities && ch != '/'
8177c478bd9Sstevel@tonic-gate 		  && (!*dirname || str_chk <= 0))
8187c478bd9Sstevel@tonic-gate 		{
8197c478bd9Sstevel@tonic-gate 		  if (print_possibilities > 0)
8207c478bd9Sstevel@tonic-gate 		    print_possibilities = -print_possibilities;
8217c478bd9Sstevel@tonic-gate 		  print_a_completion (dp->name);
8227c478bd9Sstevel@tonic-gate 		}
8237c478bd9Sstevel@tonic-gate # endif
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	      dp->name[dp->name_len] = saved_c;
8267c478bd9Sstevel@tonic-gate 	    }
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate       while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate       current_ino = dp->inode;
8327c478bd9Sstevel@tonic-gate       *(dirname = rest) = ch;
8337c478bd9Sstevel@tonic-gate     }
8347c478bd9Sstevel@tonic-gate   /* never get here */
8357c478bd9Sstevel@tonic-gate }
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate #endif /* FSYS_EXT2_FS */
838