📄 namei.c
字号:
}static loff_t vfat_find_free_slots(struct inode *dir,int slots){ struct super_block *sb = dir->i_sb; loff_t offset, curr; struct msdos_dir_entry *de; struct buffer_head *bh; struct inode *inode; int ino; int row; int done; int res; int added; PRINTK(("vfat_find_free_slots: find %d free slots\n", slots)); offset = curr = 0; bh = NULL; row = 0; ino = fat_get_entry(dir,&curr,&bh,&de); for (added = 0; added < 2; added++) { while (ino > -1) { done = IS_FREE(de->name); if (done) { inode = iget(sb,ino); if (inode) { /* Directory slots of busy deleted files aren't available yet. */ done = !MSDOS_I(inode)->i_busy; /* PRINTK(("inode %d still busy\n", ino)); */ } iput(inode); } if (done) { row++; if (row == slots) { fat_brelse(sb, bh); /* printk("----- Free offset at %d\n", offset); */ return offset; } } else { row = 0; offset = curr; } ino = fat_get_entry(dir,&curr,&bh,&de); } if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32)) return -ENOSPC; if ((res = fat_add_cluster(dir)) < 0) return res; ino = fat_get_entry(dir,&curr,&bh,&de); } return -ENOSPC;}/* Translate a string, including coded sequences into Unicode */static intxlate_to_uni(const char *name, int len, char *outname, int *outlen, int escape, int utf8, struct nls_table *nls){ 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) { /* XXX: i is incorrectly computed. */ 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]; } PRINTK(("vfat_fill_long_slots 3: slots=%d\n",*slots)); for (ps = ds, slot = *slots; slot > 0; slot--, ps++) { int end, j; PRINTK(("vfat_fill_long_slots 4\n")); ps->id = slot; ps->attr = ATTR_EXT; ps->reserved = 0; ps->alias_checksum = cksum; ps->start = 0; PRINTK(("vfat_fill_long_slots 5: uniname=%s\n",uniname)); offset = (slot - 1) * 26; ip = &uniname[offset]; j = offset; end = 0; for (i = 0; i < 10; i += 2) { ps->name0_4[i] = *ip++; ps->name0_4[i+1] = *ip++; } PRINTK(("vfat_fill_long_slots 6\n")); for (i = 0; i < 12; i += 2) { ps->name5_10[i] = *ip++; ps->name5_10[i+1] = *ip++; } PRINTK(("vfat_fill_long_slots 7\n")); for (i = 0; i < 4; i += 2) { ps->name11_12[i] = *ip++; ps->name11_12[i+1] = *ip++; } } PRINTK(("vfat_fill_long_slots 8\n")); ds[0].id |= 0x40; de = (struct msdos_dir_entry *) ps; PRINTK(("vfat_fill_long_slots 9\n")); strncpy(de->name, msdos_name, MSDOS_NAME); free_page(page); return 0;} static int vfat_build_slots(struct inode *dir,const char *name,int len, struct msdos_dir_slot *ds, int *slots, int *is_long){ struct msdos_dir_entry *de; char msdos_name[MSDOS_NAME]; int res, xlate, utf8; struct nls_table *nls; PRINTK(("Entering vfat_build_slots: name=%s, len=%d\n", name, len)); 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; *is_long = 0; if (len == 1 && name[0] == '.') { strncpy(de->name, MSDOS_DOT, MSDOS_NAME); } else if (len == 2 && name[0] == '.' && name[1] == '.') { strncpy(de->name, MSDOS_DOT, MSDOS_NAME); } else { PRINTK(("vfat_build_slots 4\n")); res = vfat_valid_shortname(name, len, 1, utf8); if (res > -1) { PRINTK(("vfat_build_slots 5a\n")); res = vfat_format_name(name, len, de->name, 1, utf8); PRINTK(("vfat_build_slots 5b\n")); } else { res = vfat_create_shortname(dir, name, len, msdos_name, utf8); if (res < 0) { return res; } res = vfat_valid_longname(name, len, 1, xlate); if (res < 0) { return res; } *is_long = 1; return vfat_fill_long_slots(ds, name, len, msdos_name, slots, xlate, utf8, nls); } } return 0;}static int vfat_readdir_cb( filldir_t filldir, void * buf, const char * name, int name_len, int is_long, off_t offset, off_t short_offset, int long_slots, ino_t ino){ struct vfat_find_info *vf = (struct vfat_find_info *) buf; const char *s1, *s2; int i;#ifdef DEBUG if (debug) printk("cb: vf.name=%s, len=%d, name=%s, name_len=%d\n", vf->name, vf->len, name, name_len);#endif /* Filenames cannot end in '.' or we treat like it has none */ if (vf->len != name_len) { if ((vf->len != name_len + 1) || (vf->name[name_len] != '.')) { return 0; } } s1 = name; s2 = vf->name; for (i = 0; i < name_len; i++) { if (vf->new_filename && !vf->posix) { if (tolower(*s1) != tolower(*s2)) return 0; } else { if (*s1 != *s2) return 0; } s1++; s2++; } vf->found = 1; vf->is_long = is_long; vf->offset = (offset == 2) ? 0 : offset; vf->short_offset = (short_offset == 2) ? 0 : short_offset; vf->long_slots = long_slots; vf->ino = ino; return -1;}static int vfat_find(struct inode *dir,const char *name,int len, int find_long, int new_filename,int is_dir,struct slot_info *sinfo_out){ struct super_block *sb = dir->i_sb; struct vfat_find_info vf; struct file fil; struct buffer_head *bh; struct msdos_dir_entry *de; struct msdos_dir_slot *ps; loff_t offset; struct msdos_dir_slot *ds; int is_long; int slots, slot; int res; PRINTK(("Entering vfat_find\n")); ds = (struct msdos_dir_slot *) kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL); if (ds == NULL) return -ENOMEM; fil.f_pos = 0; vf.name = name; vf.len = len; vf.new_filename = new_filename; vf.found = 0; vf.posix = MSDOS_SB(sb)->options.posixfs; res = fat_readdirx(dir,&fil,(void *)&vf,vfat_readdir_cb,NULL,1,find_long,0); PRINTK(("vfat_find: Debug 1\n")); if (res < 0) goto cleanup; if (vf.found) { if (new_filename) { res = -EEXIST; goto cleanup; } sinfo_out->longname_offset = vf.offset; sinfo_out->shortname_offset = vf.short_offset; sinfo_out->is_long = vf.is_long; sinfo_out->long_slots = vf.long_slots; sinfo_out->total_slots = vf.long_slots + 1; sinfo_out->ino = vf.ino; PRINTK(("vfat_find: Debug 2\n")); res = 0; goto cleanup; } PRINTK(("vfat_find: Debug 3\n")); if (!vf.found && !new_filename) { res = -ENOENT; goto cleanup; } res = vfat_build_slots(dir, name, len, ds, &slots, &is_long); if (res < 0) goto cleanup; de = (struct msdos_dir_entry *) ds; bh = NULL; if (new_filename) { PRINTK(("vfat_find: create file 1\n")); if (is_long) slots++; offset = vfat_find_free_slots(dir, slots); if (offset < 0) { res = offset; goto cleanup; } PRINTK(("vfat_find: create file 2\n")); /* Now create the new entry */ bh = NULL; for (slot = 0, ps = ds; slot < slots; slot++, ps++) { PRINTK(("vfat_find: create file 3, slot=%d\n",slot)); sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de); if (sinfo_out->ino < 0) { PRINTK(("vfat_find: problem\n")); res = sinfo_out->ino; goto cleanup; } memcpy(de, ps, sizeof(struct msdos_dir_slot)); fat_mark_buffer_dirty(sb, bh, 1); } PRINTK(("vfat_find: create file 4\n")); dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME; dir->i_dirt = 1; PRINTK(("vfat_find: create file 5\n")); 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); fat_brelse(sb, bh); sinfo_out->is_long = (slots > 1) ? 1 : 0; if (sinfo_out->is_long) { sinfo_out->long_slots = slots - 1; } else { sinfo_out->long_slots = 0; } sinfo_out->total_slots = slots; sinfo_out->shortname_offset = offset - sizeof(struct msdos_dir_slot); sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots; res = 0; return 0; } else { res = -ENOENT; }cleanup: kfree(ds); return res;}int vfat_lookup(struct inode *dir,const char *name,int len, struct inode **result){ int res, ino; struct inode *next; struct slot_info sinfo; PRINTK (("vfat_lookup: name=%s, len=%d\n", name, len)); *result = NULL; if (!dir) return -ENOENT; if (!S_ISDIR(dir->i_mode)) { iput(dir); return -ENOENT; } PRINTK (("vfat_lookup 2\n")); if (len == 1 && name[0] == '.') { *result = dir; return 0; } if (len == 2 && name[0] == '.' && name[1] == '.') { ino = fat_parent_ino(dir,0); iput(dir); if (ino < 0) return ino; if (!(*result = iget(dir->i_sb,ino))) return -EACCES; return 0; } if (dcache_lookup(dir, name, len, (unsigned long *) &ino) && ino) { iput(dir); if (!(*result = iget(dir->i_sb, ino))) return -EACCES; return 0; } PRINTK (("vfat_lookup 3\n")); if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0) { iput(dir); return res; } PRINTK (("vfat_lookup 4.5\n")); if (!(*result = iget(dir->i_sb,sinfo.ino))) { iput(dir); return -EACCES; } PRINTK (("vfat_lookup 5\n")); if (!(*result)->i_sb || ((*result)->i_sb->s_magic != MSDOS_SUPER_MAGIC)) { /* crossed a mount point into a non-msdos fs */ iput(dir); return 0; } if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */ iput(*result); iput(dir); return -ENOENT; } PRINTK (("vfat_lookup 6\n")); while (MSDOS_I(*result)->i_old) { next = MSDOS_I(*result)->i_old; iput(*result); if (!(*result = iget(next->i_sb,next->i_ino))) { fat_fs_panic(dir->i_sb,"vfat_lookup: Can't happen"); iput(dir); return -ENOENT; } } iput(dir); return 0;}static int vfat_create_entry(struct inode *dir,const char *name,int len, int is_dir, struct inode **result){ struct super_block *sb = dir->i_sb; int res,ino; loff_t offset; struct buffer_head *bh; struct msdos_dir_entry *de; struct slot_info sinfo; PRINTK(("vfat_create_entry 1\n")); res = vfat_find(dir, name, len, 1, 1, is_dir, &sinfo); if (res < 0) { return res; } offset = sinfo.shortname_offset; PRINTK(("vfat_create_entry 2\n")); bh = NULL; ino = fat_get_entry(dir, &offset, &bh, &de); if (ino < 0) { PRINTK(("vfat_mkdir problem\n")); if (bh) fat_brelse(sb, bh); return ino; } PRINTK(("vfat_create_entry 3\n")); if ((*result = iget(dir->i_sb,ino)) != NULL) vfat_read_inode(*result); fat_brelse(sb, bh); if (!*result) return -EIO; (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime = CURRENT_TIME; (*result)->i_dirt = 1; (*result)->i_version = ++event; dir->i_version = event; dcache_add(dir, name, len, ino); return 0;}int vfat_create(struct inode *dir,const char *name,int len,int mode, struct inode **result){ int res; if (!dir) return -ENOENT; fat_lock_creation(); res = vfat_create_entry(dir,name,len,0,result); if (res < 0) PRINTK(("vfat_create: unable to get new entry\n")); fat_unlock_creation(); iput(dir); return res;}static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent, struct buffer_head *bh, struct msdos_dir_entry *de,int ino,const char *name, int isdot){ struct super_block *sb = dir->i_sb; struct inode *dot; PRINTK(("vfat_create_a_dotdir 1\n")); /* * XXX all times should be set by caller upon successful completion. */ dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; dir->i_dirt = 1; memcpy(de->name,name,MSDOS_NAME); de->lcase = 0; de->attr = ATTR_DIR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -