namei.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,127 行 · 第 1/2 页
C
1,127 行
continue; } return -EINVAL; } *op++ = ec & 0xFF; *op++ = ec >> 8; ip += 5; i += 5; } else { if ((charlen = nls->char2uni(ip, len-i, (wchar_t *)op)) < 0) return -EINVAL; ip += charlen; i += charlen; op += 2; } } } else { for (i = 0, ip = name, op = outname, *outlen = 0; i < len && *outlen <= 260; i++, *outlen += 1) { *op++ = *ip++; *op++ = 0; } } } if (*outlen > 260) return -ENAMETOOLONG; *longlen = *outlen; if (*outlen % 13) { *op++ = 0; *op++ = 0; *outlen += 1; if (*outlen % 13) { fill = 13 - (*outlen % 13); for (i = 0; i < fill; i++) { *op++ = 0xff; *op++ = 0xff; } *outlen += fill; } } return 0;}static int vfat_build_slots(struct inode *dir, const unsigned char *name, int len, struct msdos_dir_slot *ds, int *slots, int is_dir){ struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb); struct fat_mount_options *opts = &sbi->options; struct msdos_dir_slot *ps; struct msdos_dir_entry *de; unsigned long page; unsigned char cksum, lcase; unsigned char msdos_name[MSDOS_NAME]; wchar_t *uname; int res, slot, ulen, usize, i; loff_t offset; *slots = 0; if (!vfat_valid_longname(name, len)) return -EINVAL; if(!(page = __get_free_page(GFP_KERNEL))) return -ENOMEM; uname = (wchar_t *)page; res = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize, opts->unicode_xlate, opts->utf8, sbi->nls_io); if (res < 0) goto out_free; res = vfat_is_used_badchars(uname, ulen); if (res < 0) goto out_free; res = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen, msdos_name, &lcase); if (res < 0) goto out_free; else if (res == 1) { de = (struct msdos_dir_entry *)ds; res = 0; goto shortname; } /* build the entry of long file name */ *slots = usize / 13; for (cksum = i = 0; i < 11; i++) { cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i]; } for (ps = ds, slot = *slots; slot > 0; slot--, ps++) { ps->id = slot; ps->attr = ATTR_EXT; ps->reserved = 0; ps->alias_checksum = cksum; ps->start = 0; offset = (slot - 1) * 13; fatwchar_to16(ps->name0_4, uname + offset, 5); fatwchar_to16(ps->name5_10, uname + offset + 5, 6); fatwchar_to16(ps->name11_12, uname + offset + 11, 2); } ds[0].id |= 0x40; de = (struct msdos_dir_entry *) ps;shortname: /* build the entry of 8.3 alias name */ (*slots)++; memcpy(de->name, msdos_name, MSDOS_NAME); de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; de->lcase = lcase; de->adate = de->cdate = de->date = 0; de->ctime = de->time = 0; de->ctime_ms = 0; de->start = 0; de->starthi = 0; de->size = 0;out_free: free_page(page); return res;}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 msdos_dir_slot *dir_slots; loff_t offset; int res, slots, slot; unsigned int len; struct msdos_dir_entry *dummy_de; struct buffer_head *dummy_bh; loff_t dummy_i_pos; len = vfat_striptail_len(qname); if (len == 0) return -ENOENT; dir_slots = kmalloc(sizeof(struct msdos_dir_slot) * MSDOS_SLOTS, GFP_KERNEL); if (dir_slots == NULL) return -ENOMEM; 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_i_pos); if (offset < 0) { res = offset; goto cleanup; } brelse(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->i_pos) < 0) { res = -EIO; goto cleanup; } memcpy(*de, dir_slots + slot, sizeof(struct msdos_dir_slot)); mark_buffer_dirty(*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.tv_sec, &(*de)->time, &(*de)->date); (*de)->ctime = (*de)->time; (*de)->adate = (*de)->cdate = (*de)->date; mark_buffer_dirty(*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; unsigned int len; int res; len = vfat_striptail_len(qname); if (len == 0) return -ENOENT; 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->i_pos)>=0) return 0; res = -EIO; } return res ? res : -ENOENT;}static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ 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; lock_kernel(); 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.i_pos, &res); brelse(bh); if (res) { unlock_kernel(); return ERR_PTR(res); } alias = d_find_alias(inode); if (alias) { if (d_invalidate(alias)==0) dput(alias); else { iput(inode); unlock_kernel(); return alias; } }error: unlock_kernel(); dentry->d_op = &vfat_dentry_ops[table]; dentry->d_time = dentry->d_parent->d_inode->i_version; dentry = d_splice_alias(inode, dentry); if (dentry) { dentry->d_op = &vfat_dentry_ops[table]; dentry->d_time = dentry->d_parent->d_inode->i_version; } return dentry;}static int vfat_create(struct inode *dir, struct dentry* dentry, int mode, struct nameidata *nd){ 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; lock_kernel(); res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de); if (res < 0) goto out; inode = fat_build_inode(sb, de, sinfo.i_pos, &res); brelse(bh); if (!inode) goto out; res = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); inode->i_version++; dir->i_version++; dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry,inode);out: unlock_kernel(); return res;}static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo, struct buffer_head *bh, struct msdos_dir_entry *de){ loff_t offset, i_pos; int i; /* remove the shortname */ dir->i_mtime = dir->i_atime = CURRENT_TIME; dir->i_version++; mark_inode_dirty(dir); de->name[0] = DELETED_FLAG; mark_buffer_dirty(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, &i_pos) < 0) continue; de->name[0] = DELETED_FLAG; de->attr = ATTR_NONE; mark_buffer_dirty(bh); } brelse(bh);}static 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; lock_kernel(); res = fat_dir_empty(dentry->d_inode); if (res) goto out; res = vfat_find(dir,&dentry->d_name,&sinfo, &bh, &de); if (res < 0) goto out; res = 0; dentry->d_inode->i_nlink = 0; dentry->d_inode->i_mtime = 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--;out: unlock_kernel(); return res;}static 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; lock_kernel(); res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de); if (res < 0) goto out; dentry->d_inode->i_nlink = 0; dentry->d_inode->i_mtime = 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);out: unlock_kernel(); return res;}static 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; lock_kernel(); res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo, &bh, &de); if (res < 0) goto out; inode = fat_build_inode(sb, de, sinfo.i_pos, &res); if (!inode) goto out_brelse; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); inode->i_version++; dir->i_version++; 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_brelse: brelse(bh);out: unlock_kernel(); return res;mkdir_failed: inode->i_nlink = 0; inode->i_mtime = 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--; goto out;} static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry){ struct buffer_head *old_bh,*new_bh,*dotdot_bh; struct msdos_dir_entry *old_de,*new_de,*dotdot_de; loff_t dotdot_i_pos; 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; lock_kernel(); res = vfat_find(old_dir,&old_dentry->d_name,&old_sinfo,&old_bh,&old_de); if (res < 0) goto rename_done; is_dir = S_ISDIR(old_inode->i_mode); if (is_dir) { if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh, &dotdot_de, &dotdot_i_pos) < 0) { res = -EIO; 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_pos != sinfo.i_pos) { /* 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++; /* 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.i_pos); mark_inode_dirty(old_inode); old_dir->i_version++; 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 = cpu_to_le16(start); dotdot_de->starthi = cpu_to_le16(start>>16); mark_buffer_dirty(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: brelse(dotdot_bh); brelse(old_bh); brelse(new_bh); unlock_kernel(); return res;}static 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,};static int vfat_fill_super(struct super_block *sb, void *data, int silent){ int res; res = fat_fill_super(sb, data, silent, &vfat_dir_inode_operations, 1); if (res) return res; 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 0;}static struct super_block *vfat_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data){ return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super);}static struct file_system_type vfat_fs_type = { .owner = THIS_MODULE, .name = "vfat", .get_sb = vfat_get_sb, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV,};static int __init init_vfat_fs(void){ return register_filesystem(&vfat_fs_type);}static void __exit exit_vfat_fs(void){ unregister_filesystem(&vfat_fs_type);}MODULE_LICENSE("GPL");MODULE_DESCRIPTION("VFAT filesystem support");MODULE_AUTHOR("Gordon Chaffee");module_init(init_vfat_fs)module_exit(exit_vfat_fs)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?