文件可能比较长,呵呵。
/*
* linux/fs/namei.c
*
* (C) 1991 Linus Torvalds
*/
/*
* Some corrections by tytso.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#define ACC_MODE(x) ("/004/002/006/377"[(x)&O_ACCMODE])
/*
* comment out this line if you want names > NAME_LEN chars to be
* truncated. Else they will be disallowed.
*/
/* #define NO_TRUNCATE */
#define MAY_EXEC 1
#define MAY_WRITE 2
#define MAY_READ 4
/*
* permission()
*
* is used to check for read/write/execute permissions on a file.
* I don't know if we should look at just the euid or both euid and
* uid, but that should be easily changed.
*/
/* 检测文件访问许可权限 */
static int permission(struct m_inode * inode,int mask)
{
int mode = inode->i_mode;
/* special case: not even root can read/write a deleted file */
if (inode->i_dev && !inode->i_nlinks)
return 0;
// 如果进程的有效用户id(euid)与i 节点的用户id 相同
else if (current->euid==inode->i_uid)
// 则取文件宿主的用户访问权限
mode >>= 6;
// 如果进程的有效组id(egid)与i 节点的组id 相同
else if (current->egid==inode->i_gid)
// 则取组用户的访问权限
mode >>= 3;
// 如果上面所取的的访问权限与屏蔽码相同,或者是超级用户
if (((mode & mask & 0007) == mask) || suser())
return 1;
return 0;
}
/*
* ok, we cannot use strncmp, as the name is not in our data space.
* Thus we'll have to use match. No big problem. Match also makes
* some sanity tests.
*
* NOTE! unlike strncmp, match returns 1 for success, 0 for failure.
*/
/* 指定长度字符串比较函数,match()成功时返回1,失败时返回0 */
static int match(int len,const char * name,struct dir_entry * de)
{
register int same __asm__("ax");
if (!de || !de->inode || len > NAME_LEN)
return 0;
if (len < NAME_LEN && de->name[len])
return 0;
__asm__("cld/n/t"
"fs ; repe ; cmpsb/n/t"
"setz %%al"
:"=a" (same)
:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
:"cx","di","si");
return same;
}
/*
* find_entry()
*
* finds an entry in the specified directory with the wanted name. It
* returns the cache buffer in which the entry was found, and the entry
* itself (as a parameter - res_dir). It does NOT read the inode of the
* entry - you'll have to do that yourself if you want to.
*
* This also takes care of the few special cases due to '..'-traversal
* over a pseudo-root and a mount point.
*/
/* 从一个目录中搜索制定的目录项,在指定的目录下,查找相应的文件inode */
/* 标志。例如在/etc/目录下,查找某个文件,返回的是该文件的inode标志 */
/* 函数的返回值放在参数res_dir中 */
static struct buffer_head * find_entry(struct m_inode ** dir,
const char * name, int namelen, struct dir_entry ** res_dir)
{
int entries;
int block,i;
struct buffer_head * bh;
struct dir_entry * de;
struct super_block * sb;
// 得到namelen
#ifdef NO_TRUNCATE
if (namelen > NAME_LEN)
return NULL;
#else
if (namelen > NAME_LEN)
namelen = NAME_LEN;
#endif
// linux中目录也是文件
// 计算本目录中目录项项数entries
entries = (*dir)->i_size / (sizeof (struct dir_entry));
*res_dir = NULL; // 返回目录项结构指针
if (!namelen)
return NULL;
/* check for '..', as we might have to do some "magic" for it */
/* /* 检查目录项'..' */
if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.')
{
/* '..' in a pseudo-root results in a faked '.' (just change namelen) */
// 如果当前进程的根节点指针即是指定的目录,则将文件名修改为'.'
if ((*dir) == current->root)
namelen=1;
// 否则如果该目录的i 节点号等于ROOT_INO(1)的话, 说明是文件系统根节点
else if ((*dir)->i_num == ROOT_INO)
{
/* '..' over a mount-point results in 'dir' being exchanged for the mounted
directory-inode. NOTE! We set mounted, so that we can iput the new dir */
// 取文件系统的超级块
sb=get_super((*dir)->i_dev);
if (sb->s_imount) // 如果被安装到的i 节点存在
{
iput(*dir); // 释放原i 节点
// 让*dir 指向该被安装到的i 节点
(*dir)=sb->s_imount; // 对被安装到的i 节点进行处理
(*dir)->i_count++; // i_count加加
}
}
}
// 如果该i 节点所指向的第一个直接磁盘块号为0
if (!(block = (*dir)->i_zone[0]))
// 返回NULL,退出
return NULL;
// 从节点所在设备读取指定的目录项数据块
if (!(bh = bread((*dir)->i_dev,block)))
return NULL;
i = 0;
// 让de 指向数据块(de -- struct dir_entry)
de = (struct dir_entry *) bh->b_data;
while (i < entries) // 不超过目录中目录项数
{
// 如果当前目录项数据块已经搜索完
if ((char *)de >= BLOCK_SIZE+bh->b_data)
{
brelse(bh); // 释放当前目录项数据块
bh = NULL;
// 在读入下一目录项数据块,首先是使用*dir来得到设备上的
// 逻辑块号,然后使用函数bread来读取设备上的数据
if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) ||
!(bh = bread((*dir)->i_dev,block)))
{
i += DIR_ENTRIES_PER_BLOCK;
continue;
}
de = (struct dir_entry *) bh->b_data; // 就让de 指向该目录项数据块
}
// 如果找到匹配的目录项的话,则返回该目录项结构指针和该目录项数据块指针
if (match(namelen,name,de))
{
*res_dir = de;
return bh;
}
// 否则继续在目录项数据块中比较下一个目录项
de++;
i++;
}
// 若指定目录中的所有目录项都搜索完还没有找到相应的目录项
brelse(bh); // 释放目录项数据块
return NULL;
}
/*
* add_entry()
*
* adds a file entry to the specified dire