📄 inode1.c
字号:
/*
* JFFS -- Journalling Flash File System, Linux implementation.
*
* Copyright (C) 1999, 2000 Finn Hakansson, Axis Communications, Inc.
*
* This 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 of the License, or
* (at your option) any later version.
*
* $Id: inode.c,v 1.71 2000/01/31 11:26:46 finn Exp $
*
*/
/* inode.c -- Contains the code that is called from the VFS. */
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/jffs.h>
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/sched.h>
#include <linux/ioctl.h>
#include <linux/stat.h>
#include <linux/blkdev.h>
#include <asm/byteorder.h>
#include "jffs_fm.h"
#include "intrep.h"
#if defined(CONFIG_JFFS_FS_VERBOSE) && CONFIG_JFFS_FS_VERBOSE
#define D(x) x
#else
#define D(x)
#endif
#define D1(x)
#define D2(x)
#define D3(x)
#define ASSERT(x) x
static int jffs_remove(struct inode *dir, const char *name,
int len, int type, int must_iput);
static struct super_operations jffs_ops;
static struct file_operations jffs_file_operations;
static struct inode_operations jffs_file_inode_operations;
static struct file_operations jffs_dir_operations;
static struct inode_operations jffs_dir_inode_operations;
static struct inode_operations jffs_symlink_inode_operations;
/* Called by the VFS at mount time to initialize the whole file system. */
static struct super_block *
jffs_read_super(struct super_block *sb, void *data, int silent)
{
kdev_t dev = sb->s_dev;
printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n",
kdevname(dev));
MOD_INC_USE_COUNT;
lock_super(sb);
set_blocksize(dev, BLOCK_SIZE);
sb->s_blocksize = BLOCK_SIZE;
sb->s_blocksize_bits = BLOCK_SIZE_BITS;
sb->u.generic_sbp = (void *) 0;
/* Build the file system. */
if (jffs_build_fs(sb) < 0) {
goto jffs_sb_err1;
}
sb->s_magic = JFFS_MAGIC_SB_BITMASK;
sb->s_op = &jffs_ops;
/* Get the root directory of this file system. */
if (!(sb->s_mounted = iget(sb, JFFS_MIN_INO))) {
goto jffs_sb_err2;
}
#ifdef USE_GC
/* Do a garbage collect every time we mount. */
jffs_garbage_collect((struct jffs_control *)sb->u.generic_sbp);
#endif
unlock_super(sb);
printk(KERN_NOTICE "JFFS: Successfully mounted device %s.\n",
kdevname(dev));
return sb;
jffs_sb_err2:
jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp);
jffs_sb_err1:
unlock_super(sb);
MOD_DEC_USE_COUNT;
printk(KERN_WARNING "JFFS: Failed to mount device %s.\n",
kdevname(dev));
return 0;
}
/* This function is called when the file system is umounted. */
static void
jffs_put_super(struct super_block *sb)
{
kdev_t dev = sb->s_dev;
D2(printk("jffs_put_super()\n"));
lock_super(sb);
sb->s_dev = 0;
jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp);
unlock_super(sb);
MOD_DEC_USE_COUNT;
printk(KERN_NOTICE "JFFS: Successfully unmounted device %s.\n",
kdevname(dev));
}
/* This function is called when user commands like chmod, chgrp and
chown are executed. System calls like trunc() results in a call
to this function. */
static int
jffs_notify_change(struct inode *inode, struct iattr *iattr)
{
struct jffs_raw_inode raw_inode;
struct jffs_control *c;
struct jffs_fmcontrol *fmc;
struct jffs_file *f;
struct jffs_node *new_node;
char *name = 0;
int update_all;
int res;
f = (struct jffs_file *)inode->u.generic_ip;
ASSERT(if (!f) {
printk("jffs_notify_change(): Invalid inode number: %lu\n",
inode->i_ino);
return -1;
});
D1(printk("***jffs_notify_change(): file: \"%s\", ino: %u\n",
f->name, f->ino));
c = f->c;
fmc = c->fmc;
update_all = iattr->ia_valid & ATTR_FORCE;
if (!JFFS_ENOUGH_SPACE(fmc)) {
if (((update_all || iattr->ia_valid & ATTR_SIZE)
&& (iattr->ia_size < f->size))) {
/* See this case where someone is trying to
shrink the size of a file as an exception.
Accept it. */
}
else {
D1(printk("jffs_notify_change(): Free size = %u\n",
jffs_free_size1(fmc)
+ jffs_free_size2(fmc)));
D(printk(KERN_NOTICE "JFFS: No space left on "
"device\n"));
return -ENOSPC;
}
}
if (!(new_node = (struct jffs_node *)
kmalloc(sizeof(struct jffs_node), GFP_KERNEL))) {
D(printk("jffs_notify_change(): Allocation failed!\n"));
return -ENOMEM;
}
DJM(no_jffs_node++);
new_node->data_offset = 0;
new_node->removed_size = 0;
raw_inode.magic = JFFS_MAGIC_BITMASK;
raw_inode.ino = f->ino;
raw_inode.pino = f->pino;
raw_inode.version = f->highest_version + 1;
raw_inode.mode = f->mode;
raw_inode.uid = f->uid;
raw_inode.gid = f->gid;
raw_inode.atime = f->atime;
raw_inode.mtime = f->mtime;
raw_inode.ctime = f->ctime;
raw_inode.dsize = 0;
raw_inode.offset = 0;
raw_inode.rsize = 0;
raw_inode.dsize = 0;
raw_inode.nsize = 0;
raw_inode.nlink = f->nlink;
raw_inode.spare = 0;
raw_inode.rename = 0;
raw_inode.deleted = 0;
if (update_all || iattr->ia_valid & ATTR_MODE) {
raw_inode.mode = iattr->ia_mode;
inode->i_mode = iattr->ia_mode;
}
if (update_all || iattr->ia_valid & ATTR_UID) {
raw_inode.uid = iattr->ia_uid;
inode->i_uid = iattr->ia_uid;
}
if (update_all || iattr->ia_valid & ATTR_GID) {
raw_inode.gid = iattr->ia_gid;
inode->i_gid = iattr->ia_gid;
}
if (update_all || iattr->ia_valid & ATTR_SIZE) {
int len;
D1(printk("jffs_notify_change(): Changing size "
"to %lu bytes!\n", iattr->ia_size));
raw_inode.offset = iattr->ia_size;
/* Calculate how many bytes need to be removed from
the end. */
if (f->size < iattr->ia_size) {
len = 0;
}
else {
len = f->size - iattr->ia_size;
}
raw_inode.rsize = len;
/* The updated node will be a removal node, with
base at the new size and size of the nbr of bytes
to be removed. */
new_node->data_offset = iattr->ia_size;
new_node->removed_size = len;
inode->i_size = iattr->ia_size;
/* If we truncate a file we want to add the name. If we
always do that, we could perhaps free more space on
the flash (and besides it doesn't hurt). */
name = f->name;
raw_inode.nsize = f->nsize;
if (len) {
invalidate_inode_pages(inode);
}
inode->i_ctime = CURRENT_TIME;
inode->i_mtime = inode->i_ctime;
}
if (update_all || iattr->ia_valid & ATTR_ATIME) {
raw_inode.atime = iattr->ia_atime;
inode->i_atime = iattr->ia_atime;
}
if (update_all || iattr->ia_valid & ATTR_MTIME) {
raw_inode.mtime = iattr->ia_mtime;
inode->i_mtime = iattr->ia_mtime;
}
if (update_all || iattr->ia_valid & ATTR_CTIME) {
raw_inode.ctime = iattr->ia_ctime;
inode->i_ctime = iattr->ia_ctime;
}
/* Write this node to the flash. */
if ((res = jffs_write_node(c, new_node, &raw_inode, name, 0)) < 0) {
D(printk("jffs_notify_change(): The write failed!\n"));
kfree(new_node);
DJM(no_jffs_node--);
return res;
}
jffs_insert_node(c, f, &raw_inode, 0, new_node);
inode->i_dirt = 1;
return 0;
} /* jffs_notify_change() */
/* Get statistics of the file system. */
static void
jffs_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
{
struct statfs tmp;
struct jffs_control *c = (struct jffs_control *) sb->u.generic_sbp;
struct jffs_fmcontrol *fmc = c->fmc;
D2(printk("jffs_statfs()\n"));
c = (struct jffs_control *)sb->u.generic_sbp;
memset(&tmp, 0, sizeof(tmp));
tmp.f_type = JFFS_MAGIC_SB_BITMASK;
tmp.f_bsize = PAGE_SIZE;
tmp.f_blocks = (fmc->flash_size / BLOCK_SIZE)
- (fmc->min_free_size / BLOCK_SIZE);
tmp.f_bfree = (jffs_free_size1(fmc) / BLOCK_SIZE
+ jffs_free_size2(fmc) / BLOCK_SIZE)
- (fmc->min_free_size / BLOCK_SIZE);
/* Find out how many files there are in the filesystem. */
tmp.f_files = jffs_foreach_file(c, jffs_file_count);
tmp.f_ffree = tmp.f_bfree;
/* tmp.f_fsid = 0; */
tmp.f_namelen = JFFS_MAX_NAME_LEN;
memcpy_tofs(buf, &tmp, bufsize);
}
/* Rename a file. */
int
jffs_rename(struct inode *old_dir, const char *old_name, int old_len,
struct inode *new_dir, const char *new_name, int new_len,
int must_be_dir)
{
struct jffs_raw_inode raw_inode;
struct jffs_control *c;
struct jffs_file *old_dir_f;
struct jffs_file *new_dir_f;
struct jffs_file *del_f;
struct jffs_file *f;
struct jffs_node *node;
struct inode *inode;
int result = 0;
__u32 rename_data = 0;
D2(printk("***jffs_rename()\n"));
if (!old_dir || !old_name || !new_dir || !new_name) {
D(printk("jffs_rename(): old_dir: 0x%p, old_name: 0x%p, "
"new_dir: 0x%p, new_name: 0x%p\n",
old_dir, old_name, new_dir, new_name));
return -1;
}
c = (struct jffs_control *)old_dir->i_sb->u.generic_sbp;
ASSERT(if (!c) {
printk(KERN_ERR "jffs_rename(): The old_dir inode "
"didn't have a reference to a jffs_file struct\n");
return -1;
});
if (!JFFS_ENOUGH_SPACE(c->fmc)) {
D1(printk("jffs_rename(): Free size = %u\n",
jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
return -ENOSPC;
}
while (c->rename_lock) {
sleep_on(&c->rename_wait);
}
c->rename_lock = 1;
/* Check the lengths of the names. */
if ((old_len > JFFS_MAX_NAME_LEN) || (new_len > JFFS_MAX_NAME_LEN)) {
result = -ENAMETOOLONG;
goto jffs_rename_end;
}
/* Find the the old directory. */
if (!(old_dir_f = (struct jffs_file *)old_dir->u.generic_ip)) {
D(printk("jffs_rename(): Old dir invalid.\n"));
result = -ENOTDIR;
goto jffs_rename_end;
}
/* See if it really is a directory. */
if (!S_ISDIR(old_dir_f->mode)) {
D(printk("jffs_rename(): old_dir is not a directory.\n"));
result = -ENOTDIR;
goto jffs_rename_end;
}
/* Try to find the file to move. */
if (!(f = jffs_find_child(old_dir_f, old_name, old_len))) {
result = -ENOENT;
goto jffs_rename_end;
}
/* Try to find the new directory's node. */
if (!(new_dir_f = (struct jffs_file *)new_dir->u.generic_ip)) {
D(printk("jffs_rename(): New dir invalid.\n"));
result = -ENOTDIR;
goto jffs_rename_end;
}
/* See if the node really is a directory. */
if (!S_ISDIR(new_dir_f->mode)) {
D(printk("jffs_rename(): The new position of the node "
"is not a directory.\n"));
result = -ENOTDIR;
goto jffs_rename_end;
}
/* Create a node and initialize as much as needed. */
if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
GFP_KERNEL))) {
D(printk("jffs_rename(): Allocation failed: node == 0\n"));
result = -ENOMEM;
goto jffs_rename_end;
}
DJM(no_jffs_node++);
node->data_offset = 0;
node->removed_size = 0;
/* Initialize the raw inode. */
raw_inode.magic = JFFS_MAGIC_BITMASK;
raw_inode.ino = f->ino;
raw_inode.pino = new_dir_f->ino;
raw_inode.version = f->highest_version + 1;
raw_inode.mode = f->mode;
raw_inode.uid = current->fsuid;
raw_inode.gid = current->fsgid;
#if 0
raw_inode.uid = f->uid;
raw_inode.gid = f->gid;
#endif
raw_inode.atime = CURRENT_TIME;
raw_inode.mtime = raw_inode.atime;
raw_inode.ctime = f->ctime;
raw_inode.offset = 0;
raw_inode.dsize = 0;
raw_inode.rsize = 0;
raw_inode.nsize = new_len;
raw_inode.nlink = f->nlink;
raw_inode.spare = 0;
raw_inode.rename = 0;
raw_inode.deleted = 0;
/* See if there already exists a file with the same name as
new_name. */
if ((del_f = jffs_find_child(new_dir_f, new_name, new_len))) {
raw_inode.rename = 1;
/*raw_inode.mode = del_f->ino;*/
}
/* Write the new node to the flash memory. */
if ((result = jffs_write_node(c, node, &raw_inode, new_name,
(unsigned char*)&rename_data)) < 0) {
D(printk("jffs_rename(): Failed to write node to flash.\n"));
kfree(node);
DJM(no_jffs_node--);
goto jffs_rename_end;
}
if (raw_inode.rename) {
/* The file with the same name must be deleted. */
c->fmc->no_call_gc = 1;
if ((result = jffs_remove(new_dir, new_name, new_len,
del_f->mode, 0)) < 0) {
/* This is really bad. */
printk(KERN_ERR "JFFS: An error occurred in "
"rename().\n");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -