📄 namei.c
字号:
/* * linux/fs/namei.c * * (C) 1991 Linus Torvalds *//* * Some corrections by tytso. */#include <string.h>#include "errno.h"#include "fs.h"#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;
//我不需要用户检测
/*else if (current->euid==inode->i_uid) mode >>= 6; else if (current->egid==inode->i_gid) mode >>= 3;
*/
/*suser 应该是判断是否是超级权限的用户*/ /*if (((mode & mask & 0007) == mask) || suser()) return 1;*/
//xly
if (((mode & mask & 0007) == mask))
return 1; return 1;}/* * 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. */static int match(int len,const char * name,struct dir_entry * de){ /*register int same __asm__("ax");*/
int i; if (!de || !de->inode || len > NAME_LEN) return 0; if (len < NAME_LEN && de->name[len]) return 0;
//xly
for (i = 0;i < len; i++)
if (name[i] != de->name[i])
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;
return 1;}/* * 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. */
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;#ifdef NO_TRUNCATE if (namelen > NAME_LEN) return NULL;#else if (namelen > NAME_LEN) namelen = NAME_LEN;#endif 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; 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) { iput(*dir); (*dir)=sb->s_imount; (*dir)->i_count++; } } }
//目录项为空,退出去 if (!(block = (*dir)->i_zone[0])) return NULL;
if (!(bh = bread((*dir)->i_dev,block))) return NULL; i = 0; de = (struct dir_entry *) bh->b_data; while (i < entries) {
//如果当前目录项数据块已经搜索完,还没有找到匹配的目录项,则释放当前目录项数据块。 if ((char *)de >= BLOCK_SIZE+bh->b_data) { brelse(bh); bh = NULL;
// 在读入下一目录项数据块。若这块为空,则只要还没有搜索完目录中的所有目录项,就跳过该块,
// 继续读下一目录项数据块。若该块不空,就让de 指向该目录项数据块,继续搜索。 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; }
//是否找到
if (match(namelen,name,de)) { *res_dir = de; return bh; } de++; i++; } brelse(bh); return NULL;}
char * iname(struct m_inode * inode, char * name)
{
/**/
struct m_inode * dir;
int entries;
int block, i;
struct buffer_head * bh;
struct dir_entry * de;
//偷懒,换一下pwd
struct m_inode * old_pwd = current->pwd = inode;
current->pwd = inode;
if (!(dir = namei("..")))
return NULL;
//目录项为空,退出去
entries = dir->i_size / (sizeof (struct dir_entry));
if (!(block = dir->i_zone[0]))
return NULL;
if (!(bh = bread(dir->i_dev,block)))
return NULL;
i = 0;
de = (struct dir_entry *) bh->b_data;
while (i < entries) {
//如果当前目录项数据块已经搜索完,还没有找到匹配的目录项,则释放当前目录项数据块。
if ((char *)de >= BLOCK_SIZE+bh->b_data) {
brelse(bh);
bh = NULL;
// 在读入下一目录项数据块。若这块为空,则只要还没有搜索完目录中的所有目录项,就跳过该块,
// 继续读下一目录项数据块。若该块不空,就让de 指向该目录项数据块,继续搜索。
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;
}
//是否找到
if (de->inode == inode->i_num) {
memcpy(name, de->name, NAME_LEN-1);
brelse(bh);
current->pwd = old_pwd;
return de->name;
}
de++;
i++;
}
brelse(bh);
current->pwd = old_pwd;
return NULL;
}/* * add_entry() * * adds a file entry to the specified directory, using the same * semantics as find_entry(). It returns NULL if it failed. * * NOTE!! The inode part of 'de' is left at 0 - which means you * may not sleep between calling this and putting something into * the entry, as someone else might have used it while you slept. */static struct buffer_head * add_entry(struct m_inode * dir, const char * name, int namelen, struct dir_entry ** res_dir){ int block,i; struct buffer_head * bh; struct dir_entry * de; *res_dir = NULL;#ifdef NO_TRUNCATE if (namelen > NAME_LEN) return NULL;#else if (namelen > NAME_LEN) namelen = NAME_LEN;#endif if (!namelen) return NULL; if (!(block = dir->i_zone[0])) return NULL; if (!(bh = bread(dir->i_dev,block))) return NULL; i = 0; de = (struct dir_entry *) bh->b_data; while (1) { if ((char *)de >= BLOCK_SIZE+bh->b_data) { brelse(bh); bh = NULL; block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK); if (!block) return NULL; if (!(bh = bread(dir->i_dev,block))) { i += DIR_ENTRIES_PER_BLOCK; continue; } de = (struct dir_entry *) bh->b_data; } if (i*sizeof(struct dir_entry) >= dir->i_size) { de->inode=0; dir->i_size = (i+1)*sizeof(struct dir_entry); dir->i_dirt = 1; dir->i_ctime = CURRENT_TIME; } if (!de->inode) { dir->i_mtime = CURRENT_TIME; for (i=0; i < NAME_LEN ; i++) de->name[i]=(i<namelen)?get_fs_byte(name+i):0; bh->b_dirt = 1; *res_dir = de; return bh; } de++; i++; } brelse(bh); return NULL;}/* * get_dir() * * Getdir traverses the pathname until it hits the topmost directory. * It returns NULL on failure. */static struct m_inode * get_dir(const char * pathname){ char c; const char * thisname; struct m_inode * inode; struct buffer_head * bh; int namelen,inr,idev; struct dir_entry * de;
//和进程相关,判断权限之类操作 if (!current->root || !current->root->i_count) panic("No root inode"); if (!current->pwd || !current->pwd->i_count) panic("No cwd inode");
//如果pathname第一个字符为'/',表示给出的是绝对路径 if ((c=get_fs_byte(pathname))=='/') { inode = current->root; pathname++;
//否则相对路径 } else if (c) inode = current->pwd;
//空名 else return NULL; /* empty name is bad */
inode->i_count++; while (1) { thisname = pathname;
//判断该节点是否为目录,有访问权限 if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) { iput(inode); return NULL; }
for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++) /* nothing */ ; if (!c) return inode; if (!(bh = find_entry(&inode,thisname,namelen,&de))) { iput(inode); return NULL; } inr = de->inode; idev = inode->i_dev; brelse(bh); iput(inode); if (!(inode = iget(idev,inr))) return NULL; }}/* * dir_namei() * * dir_namei() returns the inode of the directory of the * specified name, and the name within that directory. */static struct m_inode * dir_namei(const char * pathname, int * namelen, const char ** name){ char c; const char * basename; struct m_inode * dir; if (!(dir = get_dir(pathname))) return NULL; basename = pathname; while (c=get_fs_byte(pathname++)) if (c=='/') basename=pathname; *namelen = pathname-basename-1; *name = basename; return dir;}/* * namei() * * is used by most simple commands to get the inode of a specified name. * Open, link etc use their own routines, but this is enough for things * like 'chmod' etc. */struct m_inode * namei(const char * pathname){ const char * basename; int inr,dev,namelen; struct m_inode * dir; struct buffer_head * bh; struct dir_entry * de; if (!(dir = dir_namei(pathname,&namelen,&basename))) return NULL; if (!namelen) /* special case: '/usr/' etc */ return dir; bh = find_entry(&dir,basename,namelen,&de); if (!bh) { iput(dir); return NULL; } inr = de->inode; dev = dir->i_dev; brelse(bh); iput(dir); dir=iget(dev,inr); if (dir) { dir->i_atime=CURRENT_TIME; dir->i_dirt=1; } return dir;}/* * open_namei() * * namei for open - this is in fact almost the whole open-routine. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -