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
ffz(unsigned long word)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
ext2fs_mount(void)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
ext2_rdfsb(int fsblock,int buffer)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
ext2fs_block_map(int logical_block)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
ext2fs_read(char * buf,int len)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
ext2_is_fast_symlink(void)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
ext2fs_dir(char * dirname)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