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