📄 namei.c
字号:
de->start = 0; de->starthi = 0; fat_date_unix2dos(dir->i_mtime,&de->time,&de->date); de->ctime_ms = 0; de->ctime = de->time; de->adate = de->cdate = de->date; de->size = 0; fat_mark_buffer_dirty(sb, bh, 1); if ((dot = iget(dir->i_sb,ino)) != NULL) vfat_read_inode(dot); if (!dot) return -EIO; dot->i_mtime = dot->i_atime = CURRENT_TIME; dot->i_dirt = 1; if (isdot) { dot->i_size = dir->i_size; MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start; MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart; dot->i_nlink = dir->i_nlink; } else { dot->i_size = parent->i_size; MSDOS_I(dot)->i_start = MSDOS_I(parent)->i_start; MSDOS_I(dot)->i_logstart = MSDOS_I(parent)->i_logstart; dot->i_nlink = parent->i_nlink; } iput(dot); PRINTK(("vfat_create_a_dotdir 2\n")); return 0;}static int vfat_create_dotdirs(struct inode *dir, struct inode *parent){ struct super_block *sb = dir->i_sb; int res; struct buffer_head *bh; struct msdos_dir_entry *de; loff_t offset; PRINTK(("vfat_create_dotdirs 1\n")); if ((res = fat_add_cluster(dir)) < 0) return res; PRINTK(("vfat_create_dotdirs 2\n")); offset = 0; bh = NULL; if ((res = fat_get_entry(dir,&offset,&bh,&de)) < 0) return res; PRINTK(("vfat_create_dotdirs 3\n")); res = vfat_create_a_dotdir(dir, parent, bh, de, res, MSDOS_DOT, 1); PRINTK(("vfat_create_dotdirs 4\n")); if (res < 0) { fat_brelse(sb, bh); return res; } PRINTK(("vfat_create_dotdirs 5\n")); if ((res = fat_get_entry(dir,&offset,&bh,&de)) < 0) { fat_brelse(sb, bh); return res; } PRINTK(("vfat_create_dotdirs 6\n")); res = vfat_create_a_dotdir(dir, parent, bh, de, res, MSDOS_DOTDOT, 0); PRINTK(("vfat_create_dotdirs 7\n")); fat_brelse(sb, bh); return res;}/***** See if directory is empty */static int vfat_empty(struct inode *dir){ struct super_block *sb = dir->i_sb; loff_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 (fat_get_entry(dir,&pos,&bh,&de) > -1) { /* Skip extended filename entries */ if (de->attr == ATTR_EXT) continue; if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT, MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) { fat_brelse(sb, bh); return -ENOTEMPTY; } } if (bh) fat_brelse(sb, bh); } return 0;}static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh, struct msdos_dir_entry *de,int ino){ struct super_block *sb = dir->i_sb; struct inode *inode; int res; if (ino < 0) return -EINVAL; if (!(inode = iget(dir->i_sb,ino))) return -ENOENT; if (!S_ISDIR(inode->i_mode)) { iput(inode); return -ENOTDIR; } if (dir->i_dev != inode->i_dev || dir == inode) { iput(inode); return -EBUSY; } res = vfat_empty(inode); if (res) { iput(inode); return res; } inode->i_nlink = 0; inode->i_mtime = dir->i_mtime = CURRENT_TIME; inode->i_atime = dir->i_atime = CURRENT_TIME; dir->i_nlink--; inode->i_dirt = dir->i_dirt = 1; de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, bh, 1); iput(inode); return 0;}static int vfat_unlink_free_ino(struct inode *dir,struct buffer_head *bh, struct msdos_dir_entry *de,int ino,int nospc){ struct super_block *sb = dir->i_sb; struct inode *inode; if (!(inode = iget(dir->i_sb,ino))) return -ENOENT; if ((!S_ISREG(inode->i_mode) && nospc) || IS_IMMUTABLE(inode)) { iput(inode); return -EPERM; } inode->i_nlink = 0; inode->i_mtime = dir->i_mtime = CURRENT_TIME; inode->i_atime = dir->i_atime = CURRENT_TIME; dir->i_version = ++event; MSDOS_I(inode)->i_busy = 1; inode->i_dirt = dir->i_dirt = 1; de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, bh, 1); iput(inode); return 0;}static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo, struct buffer_head **bh,struct msdos_dir_entry **de, int is_dir,int nospc){ struct super_block *sb = dir->i_sb; loff_t offset; int res, i; /* remove the shortname */ offset = sinfo->shortname_offset; res = fat_get_entry(dir, &offset, bh, de); if (res < 0) return res; if (is_dir) { res = vfat_rmdir_free_ino(dir,*bh,*de,res); } else { res = vfat_unlink_free_ino(dir,*bh,*de,res,nospc); } if (res < 0) return res; /* remove the longname */ offset = sinfo->longname_offset; for (i = sinfo->long_slots; i > 0; --i) { res = fat_get_entry(dir, &offset, bh, de); if (res < 0) { printk("vfat_remove_entry: problem 1\n"); continue; } (*de)->name[0] = DELETED_FLAG; (*de)->attr = 0; fat_mark_buffer_dirty(sb, *bh, 1); } return 0;}static int vfat_rmdirx(struct inode *dir,const char *name,int len){ struct super_block *sb = dir->i_sb; int res; struct buffer_head *bh; struct msdos_dir_entry *de; struct slot_info sinfo; bh = NULL; res = -EPERM; if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) goto rmdir_done; res = vfat_find(dir,name,len,1,0,0,&sinfo); if (res >= 0 && sinfo.total_slots > 0) { res = vfat_remove_entry(dir,&sinfo,&bh,&de,1,0); if (res > 0) { res = 0; } dir->i_version = ++event; }rmdir_done: fat_brelse(sb, bh); return res;}/***** Remove a directory */int vfat_rmdir(struct inode *dir,const char *name,int len){ int res; res = vfat_rmdirx(dir, name, len); iput(dir); return res;}static int vfat_unlinkx( struct inode *dir, const char *name, int len, int nospc) /* Flag special file ? */{ struct super_block *sb = dir->i_sb; int res; struct buffer_head *bh; struct msdos_dir_entry *de; struct slot_info sinfo; bh = NULL; res = vfat_find(dir,name,len,1,0,0,&sinfo); if (res >= 0 && sinfo.total_slots > 0) { res = vfat_remove_entry(dir,&sinfo,&bh,&de,0,nospc); if (res > 0) { res = 0; } } fat_brelse(sb, bh); return res;}int vfat_mkdir(struct inode *dir,const char *name,int len,int mode){ struct inode *inode; int res; fat_lock_creation(); if ((res = vfat_create_entry(dir,name,len,1,&inode)) < 0) { fat_unlock_creation(); iput(dir); return res; } dir->i_nlink++; inode->i_nlink = 2; /* no need to mark them dirty */ MSDOS_I(inode)->i_busy = 1; /* prevent lookups */ res = vfat_create_dotdirs(inode, dir); fat_unlock_creation(); MSDOS_I(inode)->i_busy = 0; iput(inode); iput(dir); if (res < 0) { if (vfat_rmdir(dir,name,len) < 0) fat_fs_panic(dir->i_sb,"rmdir in mkdir failed"); } return res;}/***** Unlink, as called for msdosfs */int vfat_unlink(struct inode *dir,const char *name,int len){ int res; res = vfat_unlinkx (dir,name,len,1); iput(dir); return res;}/***** Unlink, as called for uvfatfs */int vfat_unlink_uvfat(struct inode *dir,const char *name,int len){ int res; res = vfat_unlinkx (dir,name,len,0); iput(dir); return res;} int vfat_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 super_block *sb = old_dir->i_sb; struct buffer_head *old_bh,*new_bh,*dotdot_bh; struct msdos_dir_entry *old_de,*new_de,*dotdot_de; loff_t old_offset,new_offset,old_longname_offset; int old_slots,old_ino,new_ino,dotdot_ino,ino; struct inode *old_inode, *new_inode, *dotdot_inode, *walk; int res, is_dir, i; int locked = 0; struct slot_info sinfo; PRINTK(("vfat_rename 1\n")); if (old_dir == new_dir && old_len == new_len && strncmp(old_name, new_name, old_len) == 0) return 0; old_bh = new_bh = NULL; old_inode = new_inode = NULL; res = vfat_find(old_dir,old_name,old_len,1,0,0,&sinfo); PRINTK(("vfat_rename 2\n")); if (res < 0) goto rename_done; old_slots = sinfo.total_slots; old_longname_offset = sinfo.longname_offset; old_offset = sinfo.shortname_offset; old_ino = sinfo.ino; res = fat_get_entry(old_dir, &old_offset, &old_bh, &old_de); PRINTK(("vfat_rename 3\n")); if (res < 0) goto rename_done; res = -ENOENT; if (!(old_inode = iget(old_dir->i_sb,old_ino))) goto rename_done; is_dir = S_ISDIR(old_inode->i_mode); if (must_be_dir && !is_dir) goto rename_done; if (is_dir) { if ((old_dir->i_dev != new_dir->i_dev) || (old_ino == new_dir->i_ino)) { res = -EINVAL; goto rename_done; } if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO; /* prevent moving directory below itself */ while (walk->i_ino != MSDOS_ROOT_INO) { ino = fat_parent_ino(walk,1); iput(walk); if (ino < 0) { res = ino; goto rename_done; } if (ino == old_ino) { res = -EINVAL; goto rename_done; } if (!(walk = iget(new_dir->i_sb,ino))) { res = -EIO; goto rename_done; } } iput(walk); } res = vfat_find(new_dir,new_name,new_len,1,0,is_dir,&sinfo); PRINTK(("vfat_rename 4\n")); if (res > -1) { int new_is_dir; PRINTK(("vfat_rename 5\n")); /* Filename currently exists. Need to delete it */ new_offset = sinfo.shortname_offset; res = fat_get_entry(new_dir, &new_offset, &new_bh, &new_de); PRINTK(("vfat_rename 6\n")); if (res < 0) goto rename_done; if (!(new_inode = iget(new_dir->i_sb,res))) goto rename_done; new_is_dir = S_ISDIR(new_inode->i_mode); iput(new_inode); if (new_is_dir) { PRINTK(("vfat_rename 7\n")); res = vfat_rmdirx(new_dir,new_name,new_len); PRINTK(("vfat_rename 8\n")); if (res < 0) goto rename_done; } else { /* Is this the same file, different case? */ if (new_inode != old_inode) { PRINTK(("vfat_rename 9\n")); res = vfat_unlinkx(new_dir,new_name,new_len,1); PRINTK(("vfat_rename 10\n")); if (res < 0) goto rename_done; } } } PRINTK(("vfat_rename 11\n")); fat_lock_creation(); locked = 1; res = vfat_find(new_dir,new_name,new_len,1,1,is_dir,&sinfo); PRINTK(("vfat_rename 12\n")); if (res < 0) goto rename_done; new_offset = sinfo.shortname_offset; new_ino = sinfo.ino; res = fat_get_entry(new_dir, &new_offset, &new_bh, &new_de); PRINTK(("vfat_rename 13\n")); if (res < 0) goto rename_done; new_de->attr = old_de->attr; new_de->time = old_de->time; new_de->date = old_de->date; new_de->ctime_ms = old_de->ctime_ms; new_de->cdate = old_de->cdate; new_de->adate = old_de->adate; new_de->start = old_de->start; new_de->starthi = old_de->starthi; new_de->size = old_de->size; if (!(new_inode = iget(new_dir->i_sb,new_ino))) goto rename_done; PRINTK(("vfat_rename 14\n")); /* At this point, we have the inodes of the old file and the * new file. We need to transfer all information from the old * inode to the new inode and then delete the slots of the old * entry */ vfat_read_inode(new_inode); MSDOS_I(old_inode)->i_busy = 1; MSDOS_I(old_inode)->i_linked = new_inode; MSDOS_I(new_inode)->i_oldlink = old_inode; fat_cache_inval_inode(old_inode); PRINTK(("vfat_rename 15: old_slots=%d\n",old_slots)); old_inode->i_dirt = 1; old_dir->i_version = ++event; /* remove the old entry */ for (i = old_slots; i > 0; --i) { res = fat_get_entry(old_dir, &old_longname_offset, &old_bh, &old_de); if (res < 0) { printk("vfat_unlinkx: problem 1\n"); continue; } old_de->name[0] = DELETED_FLAG; old_de->attr = 0; fat_mark_buffer_dirty(sb, old_bh, 1); } PRINTK(("vfat_rename 15b\n")); fat_mark_buffer_dirty(sb, new_bh, 1); dcache_add(new_dir, new_name, new_len, new_ino); /* XXX: There is some code in the original MSDOS rename that * is not duplicated here and it might cause a problem in * certain circumstances. */ if (S_ISDIR(old_inode->i_mode)) { if ((res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh, &dotdot_de,&dotdot_ino,SCAN_ANY)) < 0) goto rename_done; if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) { fat_brelse(sb, dotdot_bh); res = -EIO; goto rename_done; } MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start; MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart; dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart); dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16); dotdot_inode->i_dirt = 1; fat_mark_buffer_dirty(sb, dotdot_bh, 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); fat_brelse(sb, dotdot_bh); } if (res > 0) res = 0;rename_done: if (locked) fat_unlock_creation(); if (old_bh) fat_brelse(sb, old_bh); if (new_bh) fat_brelse(sb, new_bh); if (old_inode) iput(old_inode); iput(old_dir); iput(new_dir); return res;}/* Public inode operations for the VFAT fs */struct inode_operations vfat_dir_inode_operations = { &fat_dir_operations, /* default directory file-ops */ vfat_create, /* create */ vfat_lookup, /* lookup */ NULL, /* link */ vfat_unlink, /* unlink */ NULL, /* symlink */ vfat_mkdir, /* mkdir */ vfat_rmdir, /* rmdir */ NULL, /* mknod */ vfat_rename, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ fat_bmap, /* bmap */ NULL, /* truncate */ NULL /* permission */};void vfat_read_inode(struct inode *inode){ fat_read_inode(inode, &vfat_dir_inode_operations);}#ifdef MODULEint init_module(void){ return init_vfat_fs();}void cleanup_module(void){ unregister_filesystem(&vfat_fs_type);}#endif /* ifdef MODULE *//* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 8 * c-brace-imaginary-offset: 0 * c-brace-offset: -8 * c-argdecl-indent: 8 * c-label-offset: -8 * c-continued-statement-offset: 8 * c-continued-brace-offset: 0 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -