|
|
1.1 ! root 1: /* ! 2: * GRUB -- GRand Unified Bootloader ! 3: * Copyright (C) 1999, 2001 Free Software Foundation, Inc. ! 4: * ! 5: * This program is free software; you can redistribute it and/or modify ! 6: * it under the terms of the GNU General Public License as published by ! 7: * the Free Software Foundation; either version 2 of the License, or ! 8: * (at your option) any later version. ! 9: * ! 10: * This program is distributed in the hope that it will be useful, ! 11: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 13: * GNU General Public License for more details. ! 14: * ! 15: * You should have received a copy of the GNU General Public License ! 16: * along with this program; if not, write to the Free Software ! 17: * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, ! 18: * MA 02110-1301, USA. ! 19: */ ! 20: ! 21: #ifdef FSYS_EXT2FS ! 22: ! 23: #include "config.h" ! 24: #include "shared.h" ! 25: #include "filesys.h" ! 26: #include "libc/byteorder.h" ! 27: ! 28: #ifdef CONFIG_DEBUG_EXT2FS ! 29: #define E2DEBUG ! 30: #endif ! 31: ! 32: static int mapblock1, mapblock2; ! 33: ! 34: /* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */ ! 35: #define DEV_BSIZE 512 ! 36: ! 37: /* include/linux/fs.h */ ! 38: #define BLOCK_SIZE 1024 /* initial block size for superblock read */ ! 39: /* made up, defaults to 1 but can be passed via mount_opts */ ! 40: #define WHICH_SUPER 1 ! 41: /* kind of from fs/ext2/super.c */ ! 42: #define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */ ! 43: ! 44: /* include/asm-i386/types.h */ ! 45: typedef __signed__ char __s8; ! 46: typedef unsigned char __u8; ! 47: typedef __signed__ short __s16; ! 48: typedef unsigned short __u16; ! 49: typedef __signed__ int __s32; ! 50: typedef unsigned int __u32; ! 51: ! 52: /* ! 53: * Constants relative to the data blocks, from ext2_fs.h ! 54: */ ! 55: #define EXT2_NDIR_BLOCKS 12 ! 56: #define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS ! 57: #define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) ! 58: #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) ! 59: #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) ! 60: ! 61: /* include/linux/ext2_fs.h */ ! 62: struct ext2_super_block ! 63: { ! 64: __u32 s_inodes_count; /* Inodes count */ ! 65: __u32 s_blocks_count; /* Blocks count */ ! 66: __u32 s_r_blocks_count; /* Reserved blocks count */ ! 67: __u32 s_free_blocks_count; /* Free blocks count */ ! 68: __u32 s_free_inodes_count; /* Free inodes count */ ! 69: __u32 s_first_data_block; /* First Data Block */ ! 70: __u32 s_log_block_size; /* Block size */ ! 71: __s32 s_log_frag_size; /* Fragment size */ ! 72: __u32 s_blocks_per_group; /* # Blocks per group */ ! 73: __u32 s_frags_per_group; /* # Fragments per group */ ! 74: __u32 s_inodes_per_group; /* # Inodes per group */ ! 75: __u32 s_mtime; /* Mount time */ ! 76: __u32 s_wtime; /* Write time */ ! 77: __u16 s_mnt_count; /* Mount count */ ! 78: __s16 s_max_mnt_count; /* Maximal mount count */ ! 79: __u16 s_magic; /* Magic signature */ ! 80: __u16 s_state; /* File system state */ ! 81: __u16 s_errors; /* Behaviour when detecting errors */ ! 82: __u16 s_pad; ! 83: __u32 s_lastcheck; /* time of last check */ ! 84: __u32 s_checkinterval; /* max. time between checks */ ! 85: __u32 s_creator_os; /* OS */ ! 86: __u32 s_rev_level; /* Revision level */ ! 87: __u16 s_def_resuid; /* Default uid for reserved blocks */ ! 88: __u16 s_def_resgid; /* Default gid for reserved blocks */ ! 89: __u32 s_reserved[235]; /* Padding to the end of the block */ ! 90: }; ! 91: ! 92: struct ext2_group_desc ! 93: { ! 94: __u32 bg_block_bitmap; /* Blocks bitmap block */ ! 95: __u32 bg_inode_bitmap; /* Inodes bitmap block */ ! 96: __u32 bg_inode_table; /* Inodes table block */ ! 97: __u16 bg_free_blocks_count; /* Free blocks count */ ! 98: __u16 bg_free_inodes_count; /* Free inodes count */ ! 99: __u16 bg_used_dirs_count; /* Directories count */ ! 100: __u16 bg_pad; ! 101: __u32 bg_reserved[3]; ! 102: }; ! 103: ! 104: struct ext2_inode ! 105: { ! 106: __u16 i_mode; /* File mode */ ! 107: __u16 i_uid; /* Owner Uid */ ! 108: __u32 i_size; /* 4: Size in bytes */ ! 109: __u32 i_atime; /* Access time */ ! 110: __u32 i_ctime; /* 12: Creation time */ ! 111: __u32 i_mtime; /* Modification time */ ! 112: __u32 i_dtime; /* 20: Deletion Time */ ! 113: __u16 i_gid; /* Group Id */ ! 114: __u16 i_links_count; /* 24: Links count */ ! 115: __u32 i_blocks; /* Blocks count */ ! 116: __u32 i_flags; /* 32: File flags */ ! 117: union ! 118: { ! 119: struct ! 120: { ! 121: __u32 l_i_reserved1; ! 122: } ! 123: linux1; ! 124: struct ! 125: { ! 126: __u32 h_i_translator; ! 127: } ! 128: hurd1; ! 129: struct ! 130: { ! 131: __u32 m_i_reserved1; ! 132: } ! 133: masix1; ! 134: } ! 135: osd1; /* OS dependent 1 */ ! 136: __u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */ ! 137: __u32 i_version; /* File version (for NFS) */ ! 138: __u32 i_file_acl; /* File ACL */ ! 139: __u32 i_dir_acl; /* Directory ACL */ ! 140: __u32 i_faddr; /* Fragment address */ ! 141: union ! 142: { ! 143: struct ! 144: { ! 145: __u8 l_i_frag; /* Fragment number */ ! 146: __u8 l_i_fsize; /* Fragment size */ ! 147: __u16 i_pad1; ! 148: __u32 l_i_reserved2[2]; ! 149: } ! 150: linux2; ! 151: struct ! 152: { ! 153: __u8 h_i_frag; /* Fragment number */ ! 154: __u8 h_i_fsize; /* Fragment size */ ! 155: __u16 h_i_mode_high; ! 156: __u16 h_i_uid_high; ! 157: __u16 h_i_gid_high; ! 158: __u32 h_i_author; ! 159: } ! 160: hurd2; ! 161: struct ! 162: { ! 163: __u8 m_i_frag; /* Fragment number */ ! 164: __u8 m_i_fsize; /* Fragment size */ ! 165: __u16 m_pad1; ! 166: __u32 m_i_reserved2[2]; ! 167: } ! 168: masix2; ! 169: } ! 170: osd2; /* OS dependent 2 */ ! 171: }; ! 172: ! 173: /* linux/posix_type.h */ ! 174: typedef long linux_off_t; ! 175: ! 176: /* linux/ext2fs.h */ ! 177: #define EXT2_NAME_LEN 255 ! 178: struct ext2_dir_entry ! 179: { ! 180: __u32 inode; /* Inode number */ ! 181: __u16 rec_len; /* Directory entry length */ ! 182: __u8 name_len; /* Name length */ ! 183: __u8 file_type; ! 184: char name[EXT2_NAME_LEN]; /* File name */ ! 185: }; ! 186: ! 187: /* ext2/super.c */ ! 188: #define EXT2_SUPER_MAGIC 0xEF53 /* include/linux/ext2_fs.h */ ! 189: #define EXT2_ROOT_INO 2 /* include/linux/ext2_fs.h */ ! 190: #define PATH_MAX 1024 /* include/linux/limits.h */ ! 191: #define MAX_LINK_COUNT 5 /* number of symbolic links to follow */ ! 192: ! 193: /* made up, these are pointers into FSYS_BUF */ ! 194: /* read once, always stays there: */ ! 195: #define SUPERBLOCK \ ! 196: ((struct ext2_super_block *)(FSYS_BUF)) ! 197: #define GROUP_DESC \ ! 198: ((struct ext2_group_desc *) \ ! 199: ((char *)SUPERBLOCK + sizeof(struct ext2_super_block))) ! 200: #define INODE \ ! 201: ((struct ext2_inode *)((char *)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK))) ! 202: #define DATABLOCK1 \ ! 203: ((char *)((char *)INODE + sizeof(struct ext2_inode))) ! 204: #define DATABLOCK2 \ ! 205: ((char *)((char *)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK))) ! 206: ! 207: /* linux/ext2_fs.h */ ! 208: #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) ! 209: #define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s))) ! 210: ! 211: /* linux/ext2_fs.h */ ! 212: #define EXT2_BLOCK_SIZE_BITS(s) (__le32_to_cpu((s)->s_log_block_size) + 10) ! 213: /* kind of from ext2/super.c */ ! 214: #define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s)) ! 215: /* linux/ext2fs.h */ ! 216: #define EXT2_DESC_PER_BLOCK(s) \ ! 217: (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) ! 218: /* linux/stat.h */ ! 219: #define S_IFMT 00170000 ! 220: #define S_IFLNK 0120000 ! 221: #define S_IFREG 0100000 ! 222: #define S_IFDIR 0040000 ! 223: #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) ! 224: #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) ! 225: #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) ! 226: ! 227: #ifdef E2DEBUG ! 228: void ! 229: dump_super(struct ext2_super_block *s) ! 230: { ! 231: printf(" superblock 0x%x:\n", s); ! 232: printf(" inodes=%d\n", __le32_to_cpu(s->s_inodes_count)); ! 233: printf(" blocks=%d\n", __le32_to_cpu(s->s_blocks_count)); ! 234: printf(" reserved=%d\n", __le32_to_cpu(s->s_r_blocks_count)); ! 235: printf(" i_free=%d\n", __le32_to_cpu(s->s_free_inodes_count)); ! 236: printf(" b_free=%d\n", __le32_to_cpu(s->s_free_blocks_count)); ! 237: printf(" first=%d\n", __le32_to_cpu(s->s_first_data_block)); ! 238: printf(" log_b_size=%d, b_size=%d\n", __le32_to_cpu(s->s_log_block_size), EXT2_BLOCK_SIZE(s)); ! 239: printf(" log_f_size=%d\n", __le32_to_cpu(s->s_log_frag_size)); ! 240: printf(" bpg=%d\n", __le32_to_cpu(s->s_blocks_per_group)); ! 241: printf(" fpg=%d\n", __le32_to_cpu(s->s_frags_per_group)); ! 242: printf(" ipg=%d\n", __le32_to_cpu(s->s_inodes_per_group)); ! 243: } ! 244: ! 245: void ! 246: dump_group_desc(struct ext2_group_desc *g) ! 247: { ! 248: printf(" group_desc 0x%x:\n", g); ! 249: printf(" b_bmap block=%d\n", __le32_to_cpu(g->bg_block_bitmap)); ! 250: printf(" i_bmap block=%d\n", __le32_to_cpu(g->bg_inode_bitmap)); ! 251: printf(" i_tab block=%d\n", __le32_to_cpu(g->bg_inode_table)); ! 252: printf(" free_blks=%d\n", __le16_to_cpu(g->bg_free_blocks_count)); ! 253: printf(" free_inodes=%d\n", __le16_to_cpu(g->bg_free_inodes_count)); ! 254: printf(" used_dirs=%d\n", __le16_to_cpu(g->bg_used_dirs_count)); ! 255: } ! 256: ! 257: void ! 258: dump_inode(struct ext2_inode *i) ! 259: { ! 260: printf(" inode 0x%x:\n", i); ! 261: printf(" mode=%o\n", __le16_to_cpu(i->i_mode)); ! 262: printf(" uid=%d\n", __le16_to_cpu(i->i_uid)); ! 263: printf(" gid=%d\n", __le16_to_cpu(i->i_gid)); ! 264: printf(" size=%d\n", __le32_to_cpu(i->i_size)); ! 265: printf(" atime=%d\n", __le32_to_cpu(i->i_atime)); ! 266: printf(" ctime=%d\n", __le32_to_cpu(i->i_ctime)); ! 267: printf(" mtime=%d\n", __le32_to_cpu(i->i_mtime)); ! 268: printf(" dtime=%d\n", __le32_to_cpu(i->i_dtime)); ! 269: printf(" links=%d\n", __le16_to_cpu(i->i_links_count)); ! 270: printf(" blocks=%d\n", __le32_to_cpu(i->i_blocks)); ! 271: printf(" flags=%d\n", __le32_to_cpu(i->i_flags)); ! 272: } ! 273: ! 274: void ! 275: dump_inode_data(unsigned char *inode, int len) ! 276: { ! 277: static char hexdigit[] = "0123456789abcdef"; ! 278: unsigned char *i; ! 279: for (i = inode; ! 280: i < (inode + len); ! 281: i++) ! 282: { ! 283: printf ("%c", hexdigit[*i >> 4]); ! 284: printf ("%c", hexdigit[*i % 16]); ! 285: if (!((i + 1 - inode) % 16)) ! 286: { ! 287: printf ("\n"); ! 288: } ! 289: else ! 290: { ! 291: printf (" "); ! 292: } ! 293: } ! 294: } ! 295: #endif ! 296: ! 297: /* check filesystem types and read superblock into memory buffer */ ! 298: int ! 299: ext2fs_mount (void) ! 300: { ! 301: int retval = 1; ! 302: ! 303: if ((((current_drive & 0x80) || (current_slice != 0)) ! 304: && (current_slice != PC_SLICE_TYPE_EXT2FS) ! 305: && (current_slice != PC_SLICE_TYPE_LINUX_RAID) ! 306: && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS)) ! 307: && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))) ! 308: || part_length < (SBLOCK + (sizeof (struct ext2_super_block) / DEV_BSIZE)) ! 309: || !devread (SBLOCK, 0, sizeof (struct ext2_super_block), ! 310: (char *) SUPERBLOCK) ! 311: || __le16_to_cpu(SUPERBLOCK->s_magic) != EXT2_SUPER_MAGIC) ! 312: retval = 0; ! 313: ! 314: return retval; ! 315: } ! 316: ! 317: /* Takes a file system block number and reads it into BUFFER. */ ! 318: static int ! 319: ext2_rdfsb (int fsblock, char * buffer) ! 320: { ! 321: #ifdef E2DEBUG ! 322: printf ("ext2_rdfsb: fsblock %d, devblock %d, size %d\n", fsblock, ! 323: fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), ! 324: EXT2_BLOCK_SIZE (SUPERBLOCK)); ! 325: #endif /* E2DEBUG */ ! 326: return devread (fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0, ! 327: EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer); ! 328: } ! 329: ! 330: /* from ! 331: ext2/inode.c:ext2_bmap() ! 332: */ ! 333: /* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into ! 334: a physical block (the location in the file system) via an inode. */ ! 335: static int ! 336: ext2fs_block_map (int logical_block) ! 337: { ! 338: ! 339: #ifdef E2DEBUG ! 340: printf ("ext2fs_block_map(%d)\n", logical_block); ! 341: #endif /* E2DEBUG */ ! 342: ! 343: /* if it is directly pointed to by the inode, return that physical addr */ ! 344: if (logical_block < EXT2_NDIR_BLOCKS) ! 345: { ! 346: #ifdef E2DEBUG ! 347: printf ("ext2fs_block_map: returning %d\n", __le32_to_cpu(INODE->i_block[logical_block])); ! 348: #endif /* E2DEBUG */ ! 349: return __le32_to_cpu(INODE->i_block[logical_block]); ! 350: } ! 351: /* else */ ! 352: logical_block -= EXT2_NDIR_BLOCKS; ! 353: /* try the indirect block */ ! 354: if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK)) ! 355: { ! 356: if (mapblock1 != 1 ! 357: && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_IND_BLOCK]), DATABLOCK1)) ! 358: { ! 359: errnum = ERR_FSYS_CORRUPT; ! 360: return -1; ! 361: } ! 362: mapblock1 = 1; ! 363: return __le32_to_cpu(((__u32 *) DATABLOCK1)[logical_block]); ! 364: } ! 365: /* else */ ! 366: logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK); ! 367: /* now try the double indirect block */ ! 368: if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2))) ! 369: { ! 370: int bnum; ! 371: if (mapblock1 != 2 ! 372: && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_DIND_BLOCK]), DATABLOCK1)) ! 373: { ! 374: errnum = ERR_FSYS_CORRUPT; ! 375: return -1; ! 376: } ! 377: mapblock1 = 2; ! 378: if ((bnum = __le32_to_cpu(((__u32 *) DATABLOCK1) ! 379: [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)])) ! 380: != mapblock2 ! 381: && !ext2_rdfsb (bnum, DATABLOCK2)) ! 382: { ! 383: errnum = ERR_FSYS_CORRUPT; ! 384: return -1; ! 385: } ! 386: mapblock2 = bnum; ! 387: return __le32_to_cpu(((__u32 *) DATABLOCK2) ! 388: [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]); ! 389: } ! 390: /* else */ ! 391: mapblock2 = -1; ! 392: logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)); ! 393: if (mapblock1 != 3 ! 394: && !ext2_rdfsb (__le32_to_cpu(INODE->i_block[EXT2_TIND_BLOCK]), DATABLOCK1)) ! 395: { ! 396: errnum = ERR_FSYS_CORRUPT; ! 397: return -1; ! 398: } ! 399: mapblock1 = 3; ! 400: if (!ext2_rdfsb (__le32_to_cpu(((__u32 *) DATABLOCK1) ! 401: [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) ! 402: * 2)]), ! 403: DATABLOCK2)) ! 404: { ! 405: errnum = ERR_FSYS_CORRUPT; ! 406: return -1; ! 407: } ! 408: if (!ext2_rdfsb (__le32_to_cpu(((__u32 *) DATABLOCK2) ! 409: [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)) ! 410: & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]), ! 411: DATABLOCK2)) ! 412: { ! 413: errnum = ERR_FSYS_CORRUPT; ! 414: return -1; ! 415: } ! 416: return __le32_to_cpu(((__u32 *) DATABLOCK2) ! 417: [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)]); ! 418: } ! 419: ! 420: /* preconditions: all preconds of ext2fs_block_map */ ! 421: int ! 422: ext2fs_read (char *buf, int len) ! 423: { ! 424: int logical_block; ! 425: int offset; ! 426: int map; ! 427: int ret = 0; ! 428: int size = 0; ! 429: ! 430: #ifdef E2DEBUG ! 431: printf("ext2fs_read(0x%x, %d)\n", buf, len); ! 432: dump_inode(INODE); ! 433: dump_inode_data((unsigned char *)INODE, sizeof (struct ext2_inode)); ! 434: #endif /* E2DEBUG */ ! 435: while (len > 0) ! 436: { ! 437: /* find the (logical) block component of our location */ ! 438: logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); ! 439: offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1); ! 440: map = ext2fs_block_map (logical_block); ! 441: #ifdef E2DEBUG ! 442: printf ("map=%d\n", map); ! 443: #endif /* E2DEBUG */ ! 444: if (map < 0) ! 445: break; ! 446: ! 447: size = EXT2_BLOCK_SIZE (SUPERBLOCK); ! 448: size -= offset; ! 449: if (size > len) ! 450: size = len; ! 451: ! 452: disk_read_func = disk_read_hook; ! 453: ! 454: devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), ! 455: offset, size, buf); ! 456: ! 457: disk_read_func = NULL; ! 458: ! 459: buf += size; ! 460: len -= size; ! 461: filepos += size; ! 462: ret += size; ! 463: } ! 464: ! 465: if (errnum) ! 466: ret = 0; ! 467: ! 468: return ret; ! 469: } ! 470: ! 471: ! 472: /* Based on: ! 473: def_blk_fops points to ! 474: blkdev_open, which calls (I think): ! 475: sys_open() ! 476: do_open() ! 477: open_namei() ! 478: dir_namei() which accesses current->fs->root ! 479: fs->root was set during original mount: ! 480: (something)... which calls (I think): ! 481: ext2_read_super() ! 482: iget() ! 483: __iget() ! 484: read_inode() ! 485: ext2_read_inode() ! 486: uses desc_per_block_bits, which is set in ext2_read_super() ! 487: also uses group descriptors loaded during ext2_read_super() ! 488: lookup() ! 489: ext2_lookup() ! 490: ext2_find_entry() ! 491: ext2_getblk() ! 492: ! 493: */ ! 494: ! 495: /* preconditions: ext2fs_mount already executed, therefore supblk in buffer ! 496: * known as SUPERBLOCK ! 497: * returns: 0 if error, nonzero iff we were able to find the file successfully ! 498: * postconditions: on a nonzero return, buffer known as INODE contains the ! 499: * inode of the file we were trying to look up ! 500: * side effects: messes up GROUP_DESC buffer area ! 501: */ ! 502: int ! 503: ext2fs_dir (char *dirname) ! 504: { ! 505: int current_ino = EXT2_ROOT_INO; /* start at the root */ ! 506: int updir_ino = current_ino; /* the parent of the current directory */ ! 507: int group_id; /* which group the inode is in */ ! 508: int group_desc; /* fs pointer to that group */ ! 509: int desc; /* index within that group */ ! 510: int ino_blk; /* fs pointer of the inode's information */ ! 511: int str_chk = 0; /* used to hold the results of a string compare */ ! 512: struct ext2_group_desc *gdp; ! 513: struct ext2_inode *raw_inode; /* inode info corresponding to current_ino */ ! 514: ! 515: char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ ! 516: int link_count = 0; ! 517: ! 518: char *rest; ! 519: char ch; /* temp char holder */ ! 520: ! 521: int off; /* offset within block of directory entry (off mod blocksize) */ ! 522: int loc; /* location within a directory */ ! 523: int blk; /* which data blk within dir entry (off div blocksize) */ ! 524: long map; /* fs pointer of a particular block from dir entry */ ! 525: struct ext2_dir_entry *dp; /* pointer to directory entry */ ! 526: ! 527: /* loop invariants: ! 528: current_ino = inode to lookup ! 529: dirname = pointer to filename component we are cur looking up within ! 530: the directory known pointed to by current_ino (if any) ! 531: */ ! 532: ! 533: #ifdef E2DEBUG ! 534: printf("****** ext2fs_dir(%s)\n", dirname); ! 535: dump_super(SUPERBLOCK); ! 536: #endif /* E2DEBUG */ ! 537: ! 538: while (1) ! 539: { ! 540: #ifdef E2DEBUG ! 541: printf ("ext2fs_dir: inode %d\n", current_ino); ! 542: printf ("ext2fs_dir: dirname=%s\n", dirname); ! 543: #endif /* E2DEBUG */ ! 544: ! 545: /* look up an inode */ ! 546: group_id = (current_ino - 1) / __le32_to_cpu(SUPERBLOCK->s_inodes_per_group); ! 547: group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK)); ! 548: desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1); ! 549: #ifdef E2DEBUG ! 550: printf ("ext2fs_dir: ipg=%d, dpb=%d\n", __le32_to_cpu(SUPERBLOCK->s_inodes_per_group), ! 551: EXT2_DESC_PER_BLOCK (SUPERBLOCK)); ! 552: printf ("ext2fs_dir: group_id=%d group_desc=%d desc=%d\n", group_id, group_desc, desc); ! 553: #endif /* E2DEBUG */ ! 554: if (!ext2_rdfsb ( ! 555: (WHICH_SUPER + group_desc + __le32_to_cpu(SUPERBLOCK->s_first_data_block)), ! 556: (char*) GROUP_DESC)) ! 557: { ! 558: return 0; ! 559: } ! 560: ! 561: #ifdef E2DEBUG ! 562: dump_group_desc(GROUP_DESC); ! 563: #endif /* E2DEBUG */ ! 564: ! 565: gdp = GROUP_DESC; ! 566: ino_blk = __le32_to_cpu(gdp[desc].bg_inode_table) + ! 567: (((current_ino - 1) % __le32_to_cpu(SUPERBLOCK->s_inodes_per_group)) ! 568: >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode))); ! 569: #ifdef E2DEBUG ! 570: printf ("ext2fs_dir: itab_blk=%d, i_in_grp=%d, log2=%d\n", ! 571: __le32_to_cpu(gdp[desc].bg_inode_table), ! 572: ((current_ino - 1) % __le32_to_cpu(SUPERBLOCK->s_inodes_per_group)), ! 573: log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode))); ! 574: printf ("ext2fs_dir: inode table fsblock=%d\n", ino_blk); ! 575: #endif /* E2DEBUG */ ! 576: if (!ext2_rdfsb (ino_blk, (char *)INODE)) ! 577: { ! 578: return 0; ! 579: } ! 580: ! 581: /* reset indirect blocks! */ ! 582: mapblock2 = mapblock1 = -1; ! 583: ! 584: raw_inode = INODE + ! 585: ((current_ino - 1) ! 586: & (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode) - 1)); ! 587: #ifdef E2DEBUG ! 588: printf ("ext2fs_dir: ipb=%d, sizeof(inode)=%d\n", ! 589: (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)), ! 590: sizeof (struct ext2_inode)); ! 591: printf ("ext2fs_dir: inode=%x, raw_inode=%x\n", INODE, raw_inode); ! 592: printf ("ext2fs_dir: offset into inode table block=%d\n", (int) raw_inode - (int) INODE); ! 593: dump_inode(raw_inode); ! 594: dump_inode_data((unsigned char *)INODE, EXT2_BLOCK_SIZE(SUPERBLOCK)); ! 595: printf ("ext2fs_dir: first word=%x\n", *((int *) raw_inode)); ! 596: #endif /* E2DEBUG */ ! 597: ! 598: /* copy inode to fixed location */ ! 599: memmove ((void *) INODE, (void *) raw_inode, sizeof (struct ext2_inode)); ! 600: ! 601: #ifdef E2DEBUG ! 602: dump_inode(INODE); ! 603: printf ("ext2fs_dir: first word=%x\n", *((int *) INODE)); ! 604: #endif /* E2DEBUG */ ! 605: ! 606: /* If we've got a symbolic link, then chase it. */ ! 607: if (S_ISLNK (__le16_to_cpu(INODE->i_mode))) ! 608: { ! 609: int len; ! 610: if (++link_count > MAX_LINK_COUNT) ! 611: { ! 612: errnum = ERR_SYMLINK_LOOP; ! 613: return 0; ! 614: } ! 615: ! 616: /* Find out how long our remaining name is. */ ! 617: len = 0; ! 618: while (dirname[len] && !isspace (dirname[len])) ! 619: len++; ! 620: ! 621: /* Get the symlink size. */ ! 622: filemax = __le32_to_cpu(INODE->i_size); ! 623: if (filemax + len > sizeof (linkbuf) - 2) ! 624: { ! 625: errnum = ERR_FILELENGTH; ! 626: return 0; ! 627: } ! 628: ! 629: if (len) ! 630: { ! 631: /* Copy the remaining name to the end of the symlink data. ! 632: Note that DIRNAME and LINKBUF may overlap! */ ! 633: memmove (linkbuf + filemax, dirname, len); ! 634: } ! 635: linkbuf[filemax + len] = '\0'; ! 636: ! 637: /* Read the symlink data. */ ! 638: if (__le32_to_cpu(INODE->i_blocks)) ! 639: { ! 640: /* Read the necessary blocks, and reset the file pointer. */ ! 641: len = file_read (linkbuf, filemax); ! 642: filepos = 0; ! 643: if (!len) ! 644: return 0; ! 645: } ! 646: else ! 647: { ! 648: /* Copy the data directly from the inode. */ ! 649: len = filemax; ! 650: memmove (linkbuf, (char *) INODE->i_block, len); ! 651: } ! 652: ! 653: #ifdef E2DEBUG ! 654: printf ("ext2fs_dir: symlink=%s\n", linkbuf); ! 655: #endif ! 656: ! 657: dirname = linkbuf; ! 658: if (*dirname == '/') ! 659: { ! 660: /* It's an absolute link, so look it up in root. */ ! 661: current_ino = EXT2_ROOT_INO; ! 662: updir_ino = current_ino; ! 663: } ! 664: else ! 665: { ! 666: /* Relative, so look it up in our parent directory. */ ! 667: current_ino = updir_ino; ! 668: } ! 669: ! 670: /* Try again using the new name. */ ! 671: continue; ! 672: } ! 673: ! 674: /* if end of filename, INODE points to the file's inode */ ! 675: if (!*dirname || isspace (*dirname)) ! 676: { ! 677: if (!S_ISREG (__le16_to_cpu(INODE->i_mode))) ! 678: { ! 679: errnum = ERR_BAD_FILETYPE; ! 680: return 0; ! 681: } ! 682: ! 683: filemax = __le32_to_cpu(INODE->i_size); ! 684: return 1; ! 685: } ! 686: ! 687: /* else we have to traverse a directory */ ! 688: updir_ino = current_ino; ! 689: ! 690: /* skip over slashes */ ! 691: while (*dirname == '/') ! 692: dirname++; ! 693: ! 694: /* if this isn't a directory of sufficient size to hold our file, abort */ ! 695: if (!(__le32_to_cpu(INODE->i_size)) || !S_ISDIR (__le16_to_cpu(INODE->i_mode))) ! 696: { ! 697: errnum = ERR_BAD_FILETYPE; ! 698: return 0; ! 699: } ! 700: ! 701: /* skip to next slash or end of filename (space) */ ! 702: for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; ! 703: rest++); ! 704: ! 705: /* look through this directory and find the next filename component */ ! 706: /* invariant: rest points to slash after the next filename component */ ! 707: *rest = 0; ! 708: loc = 0; ! 709: ! 710: do ! 711: { ! 712: ! 713: #ifdef E2DEBUG ! 714: printf ("ext2fs_dir: dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc); ! 715: #endif /* E2DEBUG */ ! 716: ! 717: /* if our location/byte offset into the directory exceeds the size, ! 718: give up */ ! 719: if (loc >= __le32_to_cpu(INODE->i_size)) ! 720: { ! 721: if (print_possibilities < 0) ! 722: { ! 723: # if 0 ! 724: putchar ('\n'); ! 725: # endif ! 726: } ! 727: else ! 728: { ! 729: errnum = ERR_FILE_NOT_FOUND; ! 730: *rest = ch; ! 731: } ! 732: return (print_possibilities < 0); ! 733: } ! 734: ! 735: /* else, find the (logical) block component of our location */ ! 736: blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK); ! 737: ! 738: /* we know which logical block of the directory entry we are looking ! 739: for, now we have to translate that to the physical (fs) block on ! 740: the disk */ ! 741: map = ext2fs_block_map (blk); ! 742: #ifdef E2DEBUG ! 743: printf ("ext2fs_dir: fs block=%d\n", map); ! 744: #endif /* E2DEBUG */ ! 745: mapblock2 = -1; ! 746: if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2)) ! 747: { ! 748: errnum = ERR_FSYS_CORRUPT; ! 749: *rest = ch; ! 750: return 0; ! 751: } ! 752: off = loc & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1); ! 753: dp = (struct ext2_dir_entry *) (DATABLOCK2 + off); ! 754: /* advance loc prematurely to next on-disk directory entry */ ! 755: loc += __le16_to_cpu(dp->rec_len); ! 756: ! 757: /* NOTE: ext2fs filenames are NOT null-terminated */ ! 758: ! 759: #ifdef E2DEBUG ! 760: printf ("ext2fs_dir: directory entry ino=%d\n", __le32_to_cpu(dp->inode)); ! 761: if (__le32_to_cpu(dp->inode)) ! 762: printf ("entry=%s\n", dp->name); ! 763: #endif /* E2DEBUG */ ! 764: ! 765: if (__le32_to_cpu(dp->inode)) ! 766: { ! 767: int saved_c = dp->name[dp->name_len]; ! 768: ! 769: dp->name[dp->name_len] = 0; ! 770: str_chk = substring (dirname, dp->name); ! 771: ! 772: # ifndef STAGE1_5 ! 773: if (print_possibilities && ch != '/' ! 774: && (!*dirname || str_chk <= 0)) ! 775: { ! 776: if (print_possibilities > 0) ! 777: print_possibilities = -print_possibilities; ! 778: print_a_completion (dp->name); ! 779: } ! 780: # endif ! 781: ! 782: dp->name[dp->name_len] = saved_c; ! 783: } ! 784: ! 785: } ! 786: while (!__le32_to_cpu(dp->inode) || (str_chk || (print_possibilities && ch != '/'))); ! 787: ! 788: current_ino = __le32_to_cpu(dp->inode); ! 789: *(dirname = rest) = ch; ! 790: } ! 791: /* never get here */ ! 792: } ! 793: ! 794: #endif /* FSYS_EXT2_FS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.