📄 namei.c
字号:
}
static int msdos_empty(struct inode *dir)
{
off_t pos;
struct buffer_head *bh;
struct msdos_dir_entry *de;
if (dir->i_count > 1)
return -EBUSY;
if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
pos = 0;
bh = NULL;
while (msdos_get_entry(dir,&pos,&bh,&de) > -1)
if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
MSDOS_NAME)) {
brelse(bh);
return -ENOTEMPTY;
}
if (bh)
brelse(bh);
}
return 0;
}
int msdos_rmdir(struct inode *dir,const char *name,int len)
{
int res,ino;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct inode *inode;
bh = NULL;
inode = NULL;
res = -EPERM;
if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
goto rmdir_done;
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
res = -ENOENT;
if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
res = -ENOTDIR;
if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
res = -EBUSY;
if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
res = msdos_empty(inode);
if (res)
goto rmdir_done;
inode->i_nlink = 0;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_nlink--;
inode->i_dirt = dir->i_dirt = 1;
de->name[0] = DELETED_FLAG;
bh->b_dirt = 1;
res = 0;
rmdir_done:
brelse(bh);
iput(dir);
iput(inode);
return res;
}
int msdos_unlink(struct inode *dir,const char *name,int len)
{
int res,ino;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct inode *inode;
bh = NULL;
inode = NULL;
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
goto unlink_done;
if (!(inode = iget(dir->i_sb,ino))) {
res = -ENOENT;
goto unlink_done;
}
if (!S_ISREG(inode->i_mode)) {
res = -EPERM;
goto unlink_done;
}
inode->i_nlink = 0;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
MSDOS_I(inode)->i_busy = 1;
inode->i_dirt = dir->i_dirt = 1;
de->name[0] = DELETED_FLAG;
bh->b_dirt = 1;
unlink_done:
brelse(bh);
iput(inode);
iput(dir);
return res;
}
static int rename_same_dir(struct inode *old_dir,char *old_name,
struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
struct msdos_dir_entry *old_de,int old_ino)
{
struct buffer_head *new_bh;
struct msdos_dir_entry *new_de;
struct inode *new_inode,*old_inode;
int new_ino,exists,error;
if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
if (*(unsigned char *) old_de->name == DELETED_FLAG) {
if (exists) brelse(new_bh);
return -ENOENT;
}
if (exists) {
if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
brelse(new_bh);
return -EIO;
}
error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ?
msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR)
? -EPERM : 0;
if (error) {
iput(new_inode);
brelse(new_bh);
return error;
}
if (S_ISDIR(new_inode->i_mode)) {
new_dir->i_nlink--;
new_dir->i_dirt = 1;
}
new_inode->i_nlink = 0;
MSDOS_I(new_inode)->i_busy = 1;
new_inode->i_dirt = 1;
new_de->name[0] = DELETED_FLAG;
new_bh->b_dirt = 1;
iput(new_inode);
brelse(new_bh);
}
memcpy(old_de->name,new_name,MSDOS_NAME);
old_bh->b_dirt = 1;
if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */
if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) {
msdos_read_inode(old_inode);
iput(old_inode);
}
return 0;
}
static int rename_diff_dir(struct inode *old_dir,char *old_name,
struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
struct msdos_dir_entry *old_de,int old_ino)
{
struct buffer_head *new_bh,*free_bh,*dotdot_bh;
struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
int new_ino,free_ino,dotdot_ino;
int error,exists,ino;
if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
if (old_ino == new_dir->i_ino) return -EINVAL;
if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
while (walk->i_ino != MSDOS_ROOT_INO) {
ino = msdos_parent_ino(walk,1);
iput(walk);
if (ino < 0) return ino;
if (ino == old_ino) return -EINVAL;
if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
}
iput(walk);
while ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) <
0) {
if (error != -ENOENT) return error;
error = msdos_add_cluster(new_dir);
if (error) return error;
}
exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
brelse(free_bh);
if (exists) brelse(new_bh);
return -EIO;
}
if (*(unsigned char *) old_de->name == DELETED_FLAG) {
iput(old_inode);
brelse(free_bh);
if (exists) brelse(new_bh);
return -ENOENT;
}
new_inode = NULL; /* to make GCC happy */
if (exists) {
if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
iput(old_inode);
brelse(new_bh);
return -EIO;
}
error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ?
msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR)
? -EPERM : 0;
if (error) {
iput(new_inode);
iput(old_inode);
brelse(new_bh);
return error;
}
new_inode->i_nlink = 0;
MSDOS_I(new_inode)->i_busy = 1;
new_inode->i_dirt = 1;
new_de->name[0] = DELETED_FLAG;
new_bh->b_dirt = 1;
}
memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
memcpy(free_de->name,new_name,MSDOS_NAME);
if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
free_de->name[0] = DELETED_FLAG;
/* Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
brelse(free_bh);
if (exists) {
iput(new_inode);
brelse(new_bh);
}
return -EIO;
}
if (exists && S_ISDIR(new_inode->i_mode)) {
new_dir->i_nlink--;
new_dir->i_dirt = 1;
}
msdos_read_inode(free_inode);
MSDOS_I(old_inode)->i_busy = 1;
cache_inval_inode(old_inode);
old_inode->i_dirt = 1;
old_de->name[0] = DELETED_FLAG;
old_bh->b_dirt = 1;
free_bh->b_dirt = 1;
if (!exists) iput(free_inode);
else {
MSDOS_I(new_inode)->i_depend = free_inode;
MSDOS_I(free_inode)->i_old = new_inode;
/* free_inode is put when putting new_inode */
iput(new_inode);
brelse(new_bh);
}
if (S_ISDIR(old_inode->i_mode)) {
if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
&dotdot_de,&dotdot_ino)) < 0) goto rename_done;
if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
brelse(dotdot_bh);
error = -EIO;
goto rename_done;
}
dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
MSDOS_I(new_dir)->i_start;
dotdot_inode->i_dirt = 1;
dotdot_bh->b_dirt = 1;
old_dir->i_nlink--;
new_dir->i_nlink++;
/* no need to mark them dirty */
dotdot_inode->i_nlink = new_dir->i_nlink;
iput(dotdot_inode);
brelse(dotdot_bh);
}
error = 0;
rename_done:
brelse(free_bh);
iput(old_inode);
return error;
}
int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
struct inode *new_dir,const char *new_name,int new_len)
{
char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
struct buffer_head *old_bh;
struct msdos_dir_entry *old_de;
int old_ino,error;
if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
old_name,old_len,old_msdos_name,1)) < 0) goto rename_done;
if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
new_name,new_len,new_msdos_name,0)) < 0) goto rename_done;
if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
&old_ino)) < 0) goto rename_done;
lock_creation();
if (old_dir == new_dir)
error = rename_same_dir(old_dir,old_msdos_name,new_dir,
new_msdos_name,old_bh,old_de,old_ino);
else error = rename_diff_dir(old_dir,old_msdos_name,new_dir,
new_msdos_name,old_bh,old_de,old_ino);
unlock_creation();
brelse(old_bh);
rename_done:
iput(old_dir);
iput(new_dir);
return error;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -