namei.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,292 行 · 第 1/2 页
C
1,292 行
int i; const unsigned char *ip; char *op; int fill; unsigned char c1, c2, c3; if (utf8) { *outlen = utf8_mbstowcs((__u16 *) outname, name, PAGE_SIZE); if (name[len-1] == '.') *outlen-=2; op = &outname[*outlen * sizeof(__u16)]; } else { if (name[len-1] == '.') len--; op = outname; if (nls) { for (i = 0, ip = name, op = outname, *outlen = 0; i < len && *outlen <= 260; i++, *outlen += 1) { if (escape && (*ip == ':')) { if (i > len - 4) return -EINVAL; c1 = fat_esc2uni[ip[1]]; c2 = fat_esc2uni[ip[2]]; c3 = fat_esc2uni[ip[3]]; if (c1 == 255 || c2 == 255 || c3 == 255) return -EINVAL; *op++ = (c1 << 4) + (c2 >> 2); *op++ = ((c2 & 0x3) << 6) + c3; ip += 4; } else { *op++ = nls->charset2uni[*ip].uni1; *op++ = nls->charset2uni[*ip].uni2; ip++; } } } 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; 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 intvfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len, char *msdos_name, int *slots, int uni_xlate, int utf8, struct nls_table *nls){ struct msdos_dir_slot *ps; struct msdos_dir_entry *de; int res; int slot; unsigned char cksum; char *uniname; const char *ip; unsigned long page; int unilen; int i; loff_t offset; if (name[len-1] == '.') len--; if(!(page = __get_free_page(GFP_KERNEL))) return -ENOMEM; uniname = (char *) page; res = xlate_to_uni(name, len, uniname, &unilen, uni_xlate, utf8, nls); if (res < 0) { free_page(page); return res; } *slots = unilen / 13; for (cksum = i = 0; i < 11; i++) { cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i]; } PRINTK3(("vfat_fill_long_slots 3: slots=%d\n",*slots)); 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) * 26; ip = &uniname[offset]; memcpy(ps->name0_4, ip, 10); memcpy(ps->name5_10, ip+10, 12); memcpy(ps->name11_12, ip+22, 4); } ds[0].id |= 0x40; de = (struct msdos_dir_entry *) ps; PRINTK3(("vfat_fill_long_slots 9\n")); strncpy(de->name, msdos_name, MSDOS_NAME); (*slots)++; free_page(page); return 0;}/* 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){ struct msdos_dir_entry *de; char msdos_name[MSDOS_NAME]; int res, xlate, utf8; struct nls_table *nls; de = (struct msdos_dir_entry *) ds; xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate; utf8 = MSDOS_SB(dir->i_sb)->options.utf8; nls = MSDOS_SB(dir->i_sb)->nls_io; *slots = 1; res = vfat_valid_longname(name, len, xlate); if (res < 0) return res; if (vfat_valid_shortname(name, len, utf8) >= 0) { vfat_format_name(name, len, de->name, utf8); return 0; } res = vfat_create_shortname(dir, name, len, msdos_name, utf8); if (res < 0) return res; return vfat_fill_long_slots(ds, name, len, msdos_name, slots, xlate, utf8, nls);}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 *ps; loff_t offset; struct msdos_dir_slot *ds; int slots, slot; int res; struct msdos_dir_entry *de1; struct buffer_head *bh1; int ino; int len; loff_t dummy; ds = (struct msdos_dir_slot *) kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL); if (ds == 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, ds, &slots); if (res < 0) goto cleanup; offset = fat_add_entries(dir, slots, &bh1, &de1, &ino); if (offset < 0) { res = offset; goto cleanup; } fat_brelse(sb, bh1); /* Now create the new entry */ *bh = NULL; for (slot = 0, ps = ds; slot < slots; slot++, ps++) { if (fat_get_entry(dir,&offset,bh,de, &sinfo_out->ino) < 0) { res = -EIO; goto cleanup; } memcpy(*de, ps, sizeof(struct msdos_dir_slot)); fat_mark_buffer_dirty(sb, *bh, 1); } 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_ms = 0; (*de)->ctime = (*de)->time; (*de)->adate = (*de)->cdate = (*de)->date; (*de)->start = 0; (*de)->starthi = 0; (*de)->size = 0; (*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH; (*de)->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT; fat_mark_buffer_dirty(sb, *bh, 1); /* slots can't be less than 1 */ sinfo_out->long_slots = slots - 1; sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots; res = 0;cleanup: kfree(ds); 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;}/* Find a hashed dentry for inode; NULL if there are none */static struct dentry *find_alias(struct inode *inode){ struct list_head *head, *next, *tmp; struct dentry *alias; head = &inode->i_dentry; next = inode->i_dentry.next; while (next != head) { tmp = next; next = tmp->next; alias = list_entry(tmp, struct dentry, d_alias); if (!list_empty(&alias->d_hash)) return dget(alias); } return NULL;}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 = 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; MSDOS_I(dir)->i_last_pos = 0; dentry->d_time = dentry->d_parent->d_inode->i_version; d_instantiate(dentry,inode); return 0;}static int vfat_create_dotdirs(struct inode *dir, struct inode *parent){ struct super_block *sb = dir->i_sb; struct buffer_head *bh; struct msdos_dir_entry *de; __u16 date, time; if ((bh = fat_add_cluster1(dir)) == NULL) return -ENOSPC; /* zeroed out, so... */ fat_date_unix2dos(dir->i_mtime,&time,&date); de = (struct msdos_dir_entry*)&bh->b_data[0]; memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME); memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME); de[0].attr = de[1].attr = ATTR_DIR; de[0].ctime = de[0].time = de[1].ctime = de[1].time = CT_LE_W(time); de[0].adate = de[0].cdate = de[0].date = de[1].adate = de[1].cdate = de[1].date = CT_LE_W(date); de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart); de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16); de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart); de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16); fat_mark_buffer_dirty(sb, bh, 1); fat_brelse(sb, bh); dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); 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; MSDOS_I(dir)->i_last_pos = 0; mark_inode_dirty(dir); de->name[0] = DELETED_FLAG; fat_mark_buffer_dirty(sb, bh, 1); /* 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, 1); } 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; if (!list_empty(&dentry->d_hash)) return -EBUSY; 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); d_delete(dentry); 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; MSDOS_I(dir)->i_last_pos = 0; dir->i_nlink++; inode->i_nlink = 2; /* no need to mark them dirty */ res = vfat_create_dotdirs(inode, dir); 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; MSDOS_I(new_dir)->i_last_pos = 0; /* 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, 1); 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 = { &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, /* followlink */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL /* permission */};struct super_block *vfat_read_super(struct super_block *sb,void *data, int silent){ struct super_block *res; MOD_INC_USE_COUNT; MSDOS_SB(sb)->options.isvfat = 1; res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations); if (res == NULL) { sb->s_dev = 0; MOD_DEC_USE_COUNT; return NULL; } if (!parse_options((char *) data, &(MSDOS_SB(sb)->options))) { MOD_DEC_USE_COUNT; } else { MSDOS_SB(sb)->put_super_callback=vfat_put_super_callback; 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;}#ifdef MODULEint init_module(void){ return init_vfat_fs();}void cleanup_module(void){ unregister_filesystem(&vfat_fs_type);}#endif /* ifdef MODULE */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?