⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fs-ecos.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * JFFS2 -- Journalling Flash File System, Version 2.
 *
 * Copyright (C) 2001-2003 Red Hat, Inc.
 *
 * Created by Dominic Ostrowski <dominic.ostrowski@3glab.com>
 * Contributors: David Woodhouse, Nick Garnett, Richard Panton.
 *
 * For licensing information, see the file 'LICENCE' in this directory.
 *
 * $Id: fs-ecos.c,v 1.37 2004/04/21 18:45:54 gthomas Exp $
 *
 */

#include <linux/types.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/jffs2.h>
#include <linux/jffs2_fs_sb.h>
#include <linux/jffs2_fs_i.h>
#include <linux/pagemap.h>
#include <linux/crc32.h>
#include "nodelist.h"

#include <errno.h>
#include <string.h>
#include <cyg/io/io.h>
#include <cyg/io/config_keys.h>

#if (__GNUC__ == 3) && (__GNUC_MINOR__ == 2) && defined (__ARM_ARCH_4__)
#error This compiler is known to be broken. Please see:
#error http://ecos.sourceware.org/ml/ecos-patches/2003-08/msg00006.html
#endif

//==========================================================================
// Forward definitions

// Filesystem operations
static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte);
static int jffs2_umount(cyg_mtab_entry * mte);
static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
		      int mode, cyg_file * fte);
#ifdef CYGOPT_FS_JFFS2_WRITE
static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir,
			    const char *name);
static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name);
static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name);
static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1,
			    const char *name1, cyg_dir dir2, const char *name2);
static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1,
			  cyg_dir dir2, const char *name2, int type);
#endif
static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
			 cyg_file * fte);
static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
		       cyg_dir * dir_out);
static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
		      struct stat *buf);
static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
			 int key, void *buf, int len);
static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
			 int key, void *buf, int len);

// File operations
static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
#ifdef CYGOPT_FS_JFFS2_WRITE
static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
#endif
static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence);
static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
			  CYG_ADDRWORD data);
static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode);
static int jffs2_fo_close(struct CYG_FILE_TAG *fp);
static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf);
static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
			    int len);
static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
			    int len);

// Directory operations
static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence);


static int jffs2_read_inode (struct _inode *inode);
static void jffs2_clear_inode (struct _inode *inode);

//==========================================================================
// Filesystem table entries

// -------------------------------------------------------------------------
// Fstab entry.
// This defines the entry in the filesystem table.
// For simplicity we use _FILESYSTEM synchronization for all accesses since
// we should never block in any filesystem operations.

#ifdef CYGOPT_FS_JFFS2_WRITE
FSTAB_ENTRY(jffs2_fste, "jffs2", 0,
	    CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILE,
	    jffs2_mount,
	    jffs2_umount,
	    jffs2_open,
	    jffs2_ops_unlink,
	    jffs2_ops_mkdir,
	    jffs2_ops_rmdir,
	    jffs2_ops_rename,
	    jffs2_ops_link,
	    jffs2_opendir,
	    jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo);
#else
FSTAB_ENTRY(jffs2_fste, "jffs2", 0,
	    CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILE,
	    jffs2_mount,
	    jffs2_umount,
	    jffs2_open,
	    (cyg_fsop_unlink *)cyg_fileio_erofs,
	    (cyg_fsop_mkdir *)cyg_fileio_erofs,
	    (cyg_fsop_rmdir *)cyg_fileio_erofs,
	    (cyg_fsop_rename *)cyg_fileio_erofs,
	    (cyg_fsop_link *)cyg_fileio_erofs,
	    jffs2_opendir,
	    jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo);
#endif

// -------------------------------------------------------------------------
// File operations.
// This set of file operations are used for normal open files.

static cyg_fileops jffs2_fileops = {
	jffs2_fo_read,
#ifdef CYGOPT_FS_JFFS2_WRITE
	jffs2_fo_write,
#else
	(cyg_fileop_write *) cyg_fileio_erofs,
#endif
	jffs2_fo_lseek,
	jffs2_fo_ioctl,
	cyg_fileio_seltrue,
	jffs2_fo_fsync,
	jffs2_fo_close,
	jffs2_fo_fstat,
	jffs2_fo_getinfo,
	jffs2_fo_setinfo
};

// -------------------------------------------------------------------------
// Directory file operations.
// This set of operations are used for open directories. Most entries
// point to error-returning stub functions. Only the read, lseek and
// close entries are functional.

static cyg_fileops jffs2_dirops = {
	jffs2_fo_dirread,
	(cyg_fileop_write *) cyg_fileio_enosys,
	jffs2_fo_dirlseek,
	(cyg_fileop_ioctl *) cyg_fileio_enosys,
	cyg_fileio_seltrue,
	(cyg_fileop_fsync *) cyg_fileio_enosys,
	jffs2_fo_close,
	(cyg_fileop_fstat *) cyg_fileio_enosys,
	(cyg_fileop_getinfo *) cyg_fileio_enosys,
	(cyg_fileop_setinfo *) cyg_fileio_enosys
};

//==========================================================================
// STATIC VARIABLES !!!

static unsigned char gc_buffer[PAGE_CACHE_SIZE];	//avoids malloc when user may be under memory pressure
static unsigned char n_fs_mounted = 0;  // a counter to track the number of jffs2 instances mounted

//==========================================================================
// Directory operations

struct jffs2_dirsearch {
	struct _inode *dir;	// directory to search
	const char *path;	// path to follow
	struct _inode *node;	// Node found
	const char *name;	// last name fragment used
	int namelen;		// name fragment length
	cyg_bool last;		// last name in path?
};

typedef struct jffs2_dirsearch jffs2_dirsearch;

//==========================================================================
// Ref count and nlink management


// FIXME: This seems like real cruft. Wouldn't it be better just to do the
// right thing?
static void icache_evict(struct _inode *root_i, struct _inode *i)
{
	struct _inode *this = root_i, *next;

 restart:
	D2(printf("icache_evict\n"));
	// If this is an absolute search path from the root,
	// remove all cached inodes with i_count of zero (these are only 
	// held where needed for dotdot filepaths)
	while (this) {
		next = this->i_cache_next;
		if (this != i && this->i_count == 0) {
			struct _inode *parent = this->i_parent;
			if (this->i_cache_next)
				this->i_cache_next->i_cache_prev = this->i_cache_prev;
			if (this->i_cache_prev)
				this->i_cache_prev->i_cache_next = this->i_cache_next;
			jffs2_clear_inode(this);
			memset(this, 0x5a, sizeof(*this));
			free(this);
			if (parent && parent != this) {
				parent->i_count--;
				this = root_i;
				goto restart;
			}
		}
		this = next;
	}
}

//==========================================================================
// Directory search

// -------------------------------------------------------------------------
// init_dirsearch()
// Initialize a dirsearch object to start a search

static void init_dirsearch(jffs2_dirsearch * ds,
			   struct _inode *dir, const char *name)
{
	D2(printf("init_dirsearch name = %s\n", name));
	D2(printf("init_dirsearch dir = %x\n", dir));

	dir->i_count++;
	ds->dir = dir;
	ds->path = name;
	ds->node = dir;
	ds->name = name;
	ds->namelen = 0;
	ds->last = false;
}

// -------------------------------------------------------------------------
// find_entry()
// Search a single directory for the next name in a path and update the
// dirsearch object appropriately.

static int find_entry(jffs2_dirsearch * ds)
{
	struct _inode *dir = ds->dir;
	const char *name = ds->path;
	const char *n = name;
	char namelen = 0;
	struct _inode *d;

	D2(printf("find_entry\n"));

	// check that we really have a directory
	if (!S_ISDIR(dir->i_mode))
		return ENOTDIR;

	// Isolate the next element of the path name. 
	while (*n != '\0' && *n != '/')
		n++, namelen++;

	// Check if this is the last path element.
	while( *n == '/') n++;
	if (*n == '\0')
		ds->last = true;

	// update name in dirsearch object
	ds->name = name;
	ds->namelen = namelen;

	if (name[0] == '.')
		switch (namelen) {
		default:
			break;
		case 2:
			// Dot followed by not Dot, treat as any other name 
			if (name[1] != '.')
				break;
			// Dot Dot 
			// Move back up the search path
			D2(printf("find_entry found ..\n"));
			ds->dir = ds->node;
			ds->node = ds->dir->i_parent;
			ds->node->i_count++;
			return ENOERR;
		case 1:
			// Dot is consumed
			D2(printf("find_entry found .\n"));
			ds->node = ds->dir;
			ds->dir->i_count++;
			return ENOERR;
		}

	// Here we have the name and its length set up.
	// Search the directory for a matching entry

	D2(printf("find_entry for name = %s\n", ds->path));
	d = jffs2_lookup(dir, name, namelen);
	D2(printf("find_entry got dir = %x\n", d));

	if (d == NULL)
		return ENOENT;

	// If it's a new directory inode, increase refcount on its parent
	if (S_ISDIR(d->i_mode) && !d->i_parent) {
		d->i_parent = dir;
		dir->i_count++;
	}

	// pass back the node we have found
	ds->node = d;
	return ENOERR;

}

// -------------------------------------------------------------------------
// jffs2_find()
// Main interface to directory search code. This is used in all file
// level operations to locate the object named by the pathname.

// Returns with use count incremented on both the sought object and 
// the directory it was found in
static int jffs2_find(jffs2_dirsearch * d)
{
	int err;

	D2(printf("jffs2_find for path =%s\n", d->path));

	// Short circuit empty paths
	if (*(d->path) == '\0') {
		d->node->i_count++;
		return ENOERR;
	}

	// iterate down directory tree until we find the object
	// we want.
	for (;;) {
		err = find_entry(d);

		if (err != ENOERR)
			return err;

		if (d->last)
			return ENOERR;

		/* We're done with it, although it we found a subdir that
		   will have caused the refcount to have been increased */
		jffs2_iput(d->dir);

		// Update dirsearch object to search next directory.
		d->dir = d->node;
		d->path += d->namelen;
		while (*(d->path) == '/')
			d->path++;	// skip dirname separators
	}
}

//==========================================================================
// Pathconf support
// This function provides support for pathconf() and fpathconf().

static int jffs2_pathconf(struct _inode *node, struct cyg_pathconf_info *info)
{
	int err = ENOERR;
	D2(printf("jffs2_pathconf\n"));

	switch (info->name) {
	case _PC_LINK_MAX:
		info->value = LINK_MAX;
		break;

	case _PC_MAX_CANON:
		info->value = -1;	// not supported
		err = EINVAL;
		break;

	case _PC_MAX_INPUT:
		info->value = -1;	// not supported
		err = EINVAL;
		break;

	case _PC_NAME_MAX:
		info->value = NAME_MAX;
		break;

	case _PC_PATH_MAX:
		info->value = PATH_MAX;
		break;

	case _PC_PIPE_BUF:
		info->value = -1;	// not supported
		err = EINVAL;
		break;

	case _PC_ASYNC_IO:
		info->value = -1;	// not supported
		err = EINVAL;
		break;

	case _PC_CHOWN_RESTRICTED:
		info->value = -1;	// not supported
		err = EINVAL;
		break;

	case _PC_NO_TRUNC:
		info->value = 0;
		break;

	case _PC_PRIO_IO:
		info->value = 0;
		break;

	case _PC_SYNC_IO:
		info->value = 0;
		break;

	case _PC_VDISABLE:
		info->value = -1;	// not supported
		err = EINVAL;
		break;

	default:
		err = EINVAL;
		break;
	}

	return err;
}

//==========================================================================
// Filesystem operations

// -------------------------------------------------------------------------
// jffs2_mount()
// Process a mount request. This mainly creates a root for the
// filesystem.
static int jffs2_read_super(struct super_block *sb)
{
	struct jffs2_sb_info *c;
	Cyg_ErrNo err;
	cyg_uint32 len;
	cyg_io_flash_getconfig_devsize_t ds;
	cyg_io_flash_getconfig_blocksize_t bs;

	D1(printk(KERN_DEBUG "jffs2: read_super\n"));

	c = JFFS2_SB_INFO(sb);

	len = sizeof (ds);
	err = cyg_io_get_config(sb->s_dev,
				CYG_IO_GET_CONFIG_FLASH_DEVSIZE, &ds, &len);
	if (err != ENOERR) {
		D1(printf
		   ("jffs2: cyg_io_get_config failed to get dev size: %d\n",
		    err));
		return err;
	}
	len = sizeof (bs);
	bs.offset = 0;
	err = cyg_io_get_config(sb->s_dev,
				CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE, &bs, &len);
	if (err != ENOERR) {
		D1(printf
		   ("jffs2: cyg_io_get_config failed to get block size: %d\n",
		    err));
		return err;
	}

	c->sector_size = bs.block_size;
	c->flash_size = ds.dev_size;
	c->cleanmarker_size = sizeof(struct jffs2_unknown_node);

	err = jffs2_do_mount_fs(c);
	if (err)
		return -err;

	D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
	sb->s_root = jffs2_iget(sb, 1);
	if (IS_ERR(sb->s_root)) {
		D1(printk(KERN_WARNING "get root inode failed\n"));
		err = PTR_ERR(sb->s_root);
		sb->s_root = NULL;
		goto out_nodes;
	}

	return 0;

      out_nodes:
	jffs2_free_ino_caches(c);
	jffs2_free_raw_node_refs(c);
	free(c->blocks);

	return err;
}

static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte)
{
	extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end;
	struct super_block *jffs2_sb = NULL;
	struct jffs2_sb_info *c;
	cyg_mtab_entry *m;
	cyg_io_handle_t t;
	Cyg_ErrNo err;

	D2(printf("jffs2_mount\n"));

	err = cyg_io_lookup(mte->devname, &t);
	if (err != ENOERR)
		return -err;

	// Iterate through the mount table to see if we're mounted
	// FIXME: this should be done better - perhaps if the superblock
	// can be stored as an inode in the icache.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -