📄 namei.c
字号:
de->size = 0;out_free: free_page(page); return res;}/* We can't get "." or ".." here - VFS takes care of those cases */static int vfat_build_slots(struct inode *dir, const char *name, int len, struct msdos_dir_slot *ds, int *slots, int is_dir){ int res, xlate; xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate; res = vfat_valid_longname(name, len, xlate); if (res < 0) return res; return vfat_fill_slots(dir, ds, name, len, slots, is_dir, xlate);}static int vfat_add_entry(struct inode *dir,struct qstr* qname, int is_dir, struct vfat_slot_info *sinfo_out, struct buffer_head **bh, struct msdos_dir_entry **de){ struct super_block *sb = dir->i_sb; struct msdos_dir_slot *dir_slots; loff_t offset; int slots, slot; int res, len; struct msdos_dir_entry *dummy_de; struct buffer_head *dummy_bh; int dummy_ino; loff_t dummy; dir_slots = (struct msdos_dir_slot *) kmalloc(sizeof(struct msdos_dir_slot) * MSDOS_SLOTS, GFP_KERNEL); if (dir_slots == NULL) return -ENOMEM; len = qname->len; while (len && qname->name[len-1] == '.') len--; res = fat_search_long(dir, qname->name, len, (MSDOS_SB(sb)->options.name_check != 's') || !MSDOS_SB(sb)->options.posixfs, &dummy, &dummy); if (res > 0) /* found */ res = -EEXIST; if (res) goto cleanup; res = vfat_build_slots(dir, qname->name, len, dir_slots, &slots, is_dir); if (res < 0) goto cleanup; /* build the empty directory entry of number of slots */ offset = fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_ino); if (offset < 0) { res = offset; goto cleanup; } fat_brelse(sb, dummy_bh); /* Now create the new entry */ *bh = NULL; for (slot = 0; slot < slots; slot++) { if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->ino) < 0) { res = -EIO; goto cleanup; } memcpy(*de, dir_slots + slot, sizeof(struct msdos_dir_slot)); fat_mark_buffer_dirty(sb, *bh); } res = 0; /* update timestamp */ dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; mark_inode_dirty(dir); fat_date_unix2dos(dir->i_mtime, &(*de)->time, &(*de)->date); (*de)->ctime = (*de)->time; (*de)->adate = (*de)->cdate = (*de)->date; fat_mark_buffer_dirty(sb, *bh); /* slots can't be less than 1 */ sinfo_out->long_slots = slots - 1; sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;cleanup: kfree(dir_slots); return res;}static int vfat_find(struct inode *dir,struct qstr* qname, struct vfat_slot_info *sinfo, struct buffer_head **last_bh, struct msdos_dir_entry **last_de){ struct super_block *sb = dir->i_sb; loff_t offset; int res,len; len = qname->len; while (len && qname->name[len-1] == '.') len--; res = fat_search_long(dir, qname->name, len, (MSDOS_SB(sb)->options.name_check != 's'), &offset,&sinfo->longname_offset); if (res>0) { sinfo->long_slots = res-1; if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->ino)>=0) return 0; res = -EIO; } return res ? res : -ENOENT;}struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry){ int res; struct vfat_slot_info sinfo; struct inode *inode; struct dentry *alias; struct buffer_head *bh = NULL; struct msdos_dir_entry *de; int table; PRINTK2(("vfat_lookup: name=%s, len=%d\n", dentry->d_name.name, dentry->d_name.len)); table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0; dentry->d_op = &vfat_dentry_ops[table]; inode = NULL; res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de); if (res < 0) { table++; goto error; } inode = fat_build_inode(dir->i_sb, de, sinfo.ino, &res); fat_brelse(dir->i_sb, bh); if (res) return ERR_PTR(res); alias = d_find_alias(inode); if (alias) { if (d_invalidate(alias)==0) dput(alias); else { iput(inode); return alias; } }error: dentry->d_op = &vfat_dentry_ops[table]; dentry->d_time = dentry->d_parent->d_inode->i_version; d_add(dentry,inode); return NULL;}int vfat_create(struct inode *dir,struct dentry* dentry,int mode){ struct super_block *sb = dir->i_sb; struct inode *inode = NULL; struct buffer_head *bh = NULL; struct msdos_dir_entry *de; struct vfat_slot_info sinfo; int res; res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de); if (res < 0) return res; inode = fat_build_inode(sb, de, sinfo.ino, &res); fat_brelse(sb, bh); if (!inode) return res; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); inode->i_version = ++event; dir->i_version = event; dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry,inode); return 0;}static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo, struct buffer_head *bh, struct msdos_dir_entry *de){ struct super_block *sb = dir->i_sb; loff_t offset; int i,ino; /* remove the shortname */ dir->i_mtime = CURRENT_TIME; dir->i_atime = CURRENT_TIME; dir->i_version = ++event; mark_inode_dirty(dir); de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, bh); /* remove the longname */ offset = sinfo->longname_offset; de = NULL; for (i = sinfo->long_slots; i > 0; --i) { if (fat_get_entry(dir, &offset, &bh, &de, &ino) < 0) continue; de->name[0] = DELETED_FLAG; de->attr = 0; fat_mark_buffer_dirty(sb, bh); } if (bh) fat_brelse(sb, bh);}int vfat_rmdir(struct inode *dir,struct dentry* dentry){ int res; struct vfat_slot_info sinfo; struct buffer_head *bh = NULL; struct msdos_dir_entry *de; res = fat_dir_empty(dentry->d_inode); if (res) return res; res = vfat_find(dir,&dentry->d_name,&sinfo, &bh, &de); if (res<0) return res; dentry->d_inode->i_nlink = 0; dentry->d_inode->i_mtime = CURRENT_TIME; dentry->d_inode->i_atime = CURRENT_TIME; fat_detach(dentry->d_inode); mark_inode_dirty(dentry->d_inode); /* releases bh */ vfat_remove_entry(dir,&sinfo,bh,de); dir->i_nlink--; return 0;}int vfat_unlink(struct inode *dir, struct dentry* dentry){ int res; struct vfat_slot_info sinfo; struct buffer_head *bh = NULL; struct msdos_dir_entry *de; PRINTK1(("vfat_unlink: %s\n", dentry->d_name.name)); res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de); if (res < 0) return res; dentry->d_inode->i_nlink = 0; dentry->d_inode->i_mtime = CURRENT_TIME; dentry->d_inode->i_atime = CURRENT_TIME; fat_detach(dentry->d_inode); mark_inode_dirty(dentry->d_inode); /* releases bh */ vfat_remove_entry(dir,&sinfo,bh,de); return res;}int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode){ struct super_block *sb = dir->i_sb; struct inode *inode = NULL; struct vfat_slot_info sinfo; struct buffer_head *bh = NULL; struct msdos_dir_entry *de; int res; res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo, &bh, &de); if (res < 0) return res; inode = fat_build_inode(sb, de, sinfo.ino, &res); if (!inode) goto out; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); inode->i_version = ++event; dir->i_version = event; dir->i_nlink++; inode->i_nlink = 2; /* no need to mark them dirty */ res = fat_new_dir(inode, dir, 1); if (res < 0) goto mkdir_failed; dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry,inode);out: fat_brelse(sb, bh); return res;mkdir_failed: inode->i_nlink = 0; inode->i_mtime = CURRENT_TIME; inode->i_atime = CURRENT_TIME; fat_detach(inode); mark_inode_dirty(inode); /* releases bh */ vfat_remove_entry(dir,&sinfo,bh,de); iput(inode); dir->i_nlink--; return res;} int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, struct inode *new_dir,struct dentry *new_dentry){ 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; int dotdot_ino; struct inode *old_inode, *new_inode; int res, is_dir; struct vfat_slot_info old_sinfo,sinfo; old_bh = new_bh = dotdot_bh = NULL; old_inode = old_dentry->d_inode; new_inode = new_dentry->d_inode; res = vfat_find(old_dir,&old_dentry->d_name,&old_sinfo,&old_bh,&old_de); PRINTK3(("vfat_rename 2\n")); if (res < 0) goto rename_done; is_dir = S_ISDIR(old_inode->i_mode); if (is_dir && (res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh, &dotdot_de,&dotdot_ino)) < 0) goto rename_done; if (new_dentry->d_inode) { res = vfat_find(new_dir,&new_dentry->d_name,&sinfo,&new_bh, &new_de); if (res < 0 || MSDOS_I(new_inode)->i_location != sinfo.ino) { /* WTF??? Cry and fail. */ printk(KERN_WARNING "vfat_rename: fs corrupted\n"); goto rename_done; } if (is_dir) { res = fat_dir_empty(new_inode); if (res) goto rename_done; } fat_detach(new_inode); } else { res = vfat_add_entry(new_dir,&new_dentry->d_name,is_dir,&sinfo, &new_bh,&new_de); if (res < 0) goto rename_done; } new_dir->i_version = ++event; /* releases old_bh */ vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de); old_bh=NULL; fat_detach(old_inode); fat_attach(old_inode, sinfo.ino); mark_inode_dirty(old_inode); old_dir->i_version = ++event; old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; mark_inode_dirty(old_dir); if (new_inode) { new_inode->i_nlink--; new_inode->i_ctime=CURRENT_TIME; } if (is_dir) { int start = MSDOS_I(new_dir)->i_logstart; dotdot_de->start = CT_LE_W(start); dotdot_de->starthi = CT_LE_W(start>>16); fat_mark_buffer_dirty(sb, dotdot_bh); old_dir->i_nlink--; if (new_inode) { new_inode->i_nlink--; } else { new_dir->i_nlink++; mark_inode_dirty(new_dir); } }rename_done: fat_brelse(sb, dotdot_bh); fat_brelse(sb, old_bh); fat_brelse(sb, new_bh); return res;}/* Public inode operations for the VFAT fs */struct inode_operations vfat_dir_inode_operations = { create: vfat_create, lookup: vfat_lookup, unlink: vfat_unlink, mkdir: vfat_mkdir, rmdir: vfat_rmdir, rename: vfat_rename, setattr: fat_notify_change,};struct super_block *vfat_read_super(struct super_block *sb,void *data, int silent){ struct super_block *res; MSDOS_SB(sb)->options.isvfat = 1; res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations); if (res == NULL) return NULL; if (parse_options((char *) data, &(MSDOS_SB(sb)->options))) { MSDOS_SB(sb)->options.dotsOK = 0; if (MSDOS_SB(sb)->options.posixfs) { MSDOS_SB(sb)->options.name_check = 's'; } if (MSDOS_SB(sb)->options.name_check != 's') { sb->s_root->d_op = &vfat_dentry_ops[0]; } else { sb->s_root->d_op = &vfat_dentry_ops[2]; } } return res;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -