📄 e2fs.c
字号:
//==========================================================================//// e2fs.c//// RedBoot support for second extended filesystem////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.// Copyright (C) 2003 Gary Thomas <gary@mind.be>//// eCos is free software; you can redistribute it and/or modify it under// the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 or (at your option) any later version.//// eCos is distributed in the hope that it will be useful, but WITHOUT ANY// WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License// for more details.//// You should have received a copy of the GNU General Public License along// with eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): msalter// Contributors: msalter// Date: 2001-07-14// Purpose: // Description: // // This code is part of RedBoot (tm).////####DESCRIPTIONEND####////==========================================================================#include <redboot.h>#include <fs/disk.h>#include <fs/e2fs.h>#define DEBUG_E2FS 0#if DEBUG_E2FS > 4static void dump_sb(struct e2fs_super_block *s);static void dump_inode(struct e2fs_inode *i);#endifstatic void *e2fs_open(partition_t *p, const char *path);static int e2fs_read(void *fp, char *buf, cyg_uint32 nbytes);// This structure is the only thing exported by this module.// These filesystem function pointers are attached to disk// partitions in the generic disk handling code.//fs_funs_t redboot_e2fs_funs = { e2fs_open, e2fs_read};// A single block buffer to be shared carefully.static cyg_uint32 blockbuf[E2FS_MAX_BLOCK_SIZE/sizeof(cyg_uint32)];#define __READ_BLOCK(n) \ PARTITION_READ(e2fs->part, E2FS_BLOCK_TO_SECTOR(e2fs, (n)), \ blockbuf, e2fs->blocksize/SECTOR_SIZE)// Get a group descriptor. Returns non-zero for success.//static inte2fs_get_gdesc(e2fs_desc_t *e2fs, cyg_uint32 group_nr, e2fs_group_t *gdesc){ cyg_uint32 sec_nr; if (group_nr < e2fs->gdesc_first || group_nr >= (e2fs->gdesc_first + E2FS_GDESC_CACHE_SIZE)) { // cache miss sec_nr = E2FS_BLOCK_TO_SECTOR(e2fs, e2fs->gdesc_block); sec_nr += (group_nr / E2FS_GDESC_PER_SECTOR);#if DEBUG_E2FS > 2 diag_printf("%s: group[%d] cache miss, sec_nr[%d]\n", __FUNCTION__, group_nr, sec_nr);#endif if (!PARTITION_READ(e2fs->part, sec_nr, (cyg_uint32 *)e2fs->gdesc_cache, sizeof(e2fs->gdesc_cache)/SECTOR_SIZE)) return 0; e2fs->gdesc_first = (group_nr / E2FS_GDESC_CACHE_SIZE) * E2FS_GDESC_CACHE_SIZE; } *gdesc = e2fs->gdesc_cache[group_nr - e2fs->gdesc_first]; return 1;}// Read the requested inode from disk. Return non-zero if successful//static inte2fs_get_inode(e2fs_desc_t *e2fs, int ino, e2fs_inode_t *ip){ cyg_uint32 offset, sec_nr, buf[SECTOR_SIZE/sizeof(cyg_uint32)]; e2fs_group_t gdesc; // get descriptor for group which this inode belongs to if (!e2fs_get_gdesc(e2fs, (ino - 1) / e2fs->inodes_per_group, &gdesc)) return 0; if (gdesc.inode_table == 0) return 0; // byte offset within group inode table offset = ((ino - 1) % e2fs->inodes_per_group) * sizeof(struct e2fs_inode); // figure out which sector holds the inode sec_nr = E2FS_BLOCK_TO_SECTOR(e2fs, SWAB_LE32(gdesc.inode_table)); sec_nr += offset / SECTOR_SIZE; // and the offset within that sector. offset %= SECTOR_SIZE;#if DEBUG_E2FS > 0x08 diag_printf("%s: ino[%d], sec_nr[%d] offset[%d]\n", __FUNCTION__, ino, sec_nr, offset);#endif if (!PARTITION_READ(e2fs->part, sec_nr, buf, 1)) return 0; *ip = *(e2fs_inode_t *)((char *)buf + offset);#if DEBUG_E2FS > 0 diag_printf("%s: inode size[%d]\n", __FUNCTION__, SWAB_LE32(ip->size));#endif return 1;}// Mount an e2fs filesystem on the given partition.// Return 0 if successful.//static inte2fs_mount(partition_t *part, e2fs_desc_t *e2fs){ int sb_block = 1; cyg_uint32 sb_buf[E2FS_MIN_BLOCK_SIZE/sizeof(cyg_uint32)]; struct e2fs_super_block *sb = (struct e2fs_super_block *)sb_buf; e2fs->part = part; if (!PARTITION_READ(part, sb_block*(E2FS_MIN_BLOCK_SIZE/SECTOR_SIZE), (cyg_uint32 *)sb, E2FS_MIN_BLOCK_SIZE/SECTOR_SIZE)) return -1; if (SWAB_LE16(sb->magic) != E2FS_SUPER_MAGIC) { diag_printf("ext2_mount: bad magic 0x%x\n", SWAB_LE16(sb->magic)); return -1; } // save some stuff for easy access e2fs->blocksize = E2FS_BLOCK_SIZE(sb); e2fs->nr_ind_blocks = (e2fs)->blocksize / sizeof(cyg_uint32); e2fs->nr_dind_blocks = e2fs->nr_ind_blocks * ((e2fs)->blocksize / sizeof(cyg_uint32)); e2fs->nr_tind_blocks = e2fs->nr_dind_blocks * ((e2fs)->blocksize / sizeof(cyg_uint32)); e2fs->blocks_per_group = SWAB_LE32(sb->blocks_per_group); e2fs->ngroups = (SWAB_LE32(sb->blocks_count) + e2fs->blocks_per_group - 1) / e2fs->blocks_per_group; e2fs->inodes_per_group = SWAB_LE32(sb->inodes_per_group); // Find the group descriptors which follow superblock e2fs->gdesc_block = ((sb_block * E2FS_MIN_BLOCK_SIZE) / e2fs->blocksize) + 1; e2fs->gdesc_first = 0; // cache group 0 initially if (!PARTITION_READ(part, E2FS_BLOCK_TO_SECTOR(e2fs,e2fs->gdesc_block), (cyg_uint32 *)e2fs->gdesc_cache, 1)) return -1;#if DEBUG_E2FS > 1 diag_printf("E2FS superblock:\n"); diag_printf(" [%d] inodes\n", SWAB_LE32(sb->inodes_count)); diag_printf(" [%d] blocks\n", SWAB_LE32(sb->blocks_count)); diag_printf(" [%d] blocksize\n", e2fs->blocksize); diag_printf(" [%d] blocks per group\n", e2fs->blocks_per_group); diag_printf(" [%d] ngroups\n", e2fs->ngroups);#endif#if DEBUG_E2FS > 4 dump_sb(sb);#endif return 0;}// Convert a block index into inode data into a block_nr.// If successful, store block number in pblknr and return non-zero.//// NB: This needs some block/sector caching to be speedier. But// that takes memory and speed is not too bad now for files// small enough to avoid double and triple indirection.//static inte2fs_inode_block(e2fs_desc_t *e2fs, e2fs_inode_t *inode, cyg_uint32 bindex, cyg_uint32 *pblknr){ if (bindex < E2FS_NR_DIR_BLOCKS) { *pblknr = SWAB_LE32(inode->block[bindex]); return 1; } bindex -= E2FS_NR_DIR_BLOCKS; if (bindex < e2fs->nr_ind_blocks) { // Indirect block if (!__READ_BLOCK(SWAB_LE32(inode->block[E2FS_IND_BLOCK]))) return 0; *pblknr = SWAB_LE32(blockbuf[bindex]); return 1; } bindex -= e2fs->nr_ind_blocks; if (bindex < e2fs->nr_dind_blocks) { // Double indirect block if (!__READ_BLOCK(SWAB_LE32(inode->block[E2FS_DIND_BLOCK]))) return 0; if (!__READ_BLOCK(SWAB_LE32(blockbuf[bindex / e2fs->nr_ind_blocks]))) return 0; *pblknr = SWAB_LE32(blockbuf[bindex % e2fs->nr_ind_blocks]); return 1; } bindex -= e2fs->nr_dind_blocks; // Triple indirect block if (!__READ_BLOCK(SWAB_LE32(inode->block[E2FS_TIND_BLOCK]))) return 0; if (!__READ_BLOCK(SWAB_LE32(blockbuf[bindex / e2fs->nr_dind_blocks]))) return 0; bindex %= e2fs->nr_dind_blocks; if (!__READ_BLOCK(SWAB_LE32(blockbuf[bindex / e2fs->nr_ind_blocks]))) return 0; *pblknr = SWAB_LE32(blockbuf[bindex % e2fs->nr_ind_blocks]); return 1;}// search a single directory block in memory looking for an// entry with the given name. Return pointer to entry if// found, NULL if not.//static e2fs_dir_entry_t *search_dir_block(e2fs_desc_t *e2fs, cyg_uint32 *blkbuf, const char *name, int namelen){ e2fs_dir_entry_t *dir; cyg_uint16 reclen, len; cyg_uint32 offset;#if DEBUG_E2FS > 0 diag_dump_buf(blkbuf, e2fs->blocksize);#endif offset = 0; while (offset < e2fs->blocksize) { dir = (e2fs_dir_entry_t *)((char *)blkbuf + offset); reclen = SWAB_LE16(dir->reclen); offset += reclen; len = dir->namelen; // terminate on anything which doesn't make sense if (reclen < 8 || (len + 8) > reclen || offset > (e2fs->blocksize + 1)) return NULL; if (dir->inode && len == namelen && !strncmp(dir->name, name, len)) return dir; } return NULL;}// Look in the given directory for an entry with the given name.// If found, return a pointer to that entry. Return NULL if not// found.//static e2fs_dir_entry_t *e2fs_dir_lookup(e2fs_desc_t *e2fs, cyg_uint32 dir_ino, const char *name, int namelen){ e2fs_inode_t inode; e2fs_dir_entry_t *dir; cyg_uint32 nblocks, last_block_size, i, block_nr, nbytes;#if DEBUG_E2FS > 0 diag_printf("%s: looking for %s [%d] in ino[%d]\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -