📄 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 > 4
static void dump_sb(struct e2fs_super_block *s);
static void dump_inode(struct e2fs_inode *i);
#endif
static 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 int
e2fs_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 int
e2fs_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 int
e2fs_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 int
e2fs_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 + -