Commit 8b59d996 authored by Hirofumi Ogawa's avatar Hirofumi Ogawa Committed by Linus Torvalds

[PATCH] FAT: Add fat_remove_entries()

This changes the fat_slot_info->nr_slot, now it's total counts which
include a shortname entry.  And this adds a fat_remove_entries()
which use the ->nr_slots.

In order not to write out the same block repeatedly,
fat_remove_entries() was rewritten from vfat_remove_entries().
Signed-off-by: default avatarOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ae4dc6df
......@@ -144,7 +144,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
struct nls_table *nls_io = MSDOS_SB(sb)->nls_io;
struct nls_table *nls_disk = MSDOS_SB(sb)->nls_disk;
wchar_t bufuname[14];
unsigned char xlate_len, long_slots;
unsigned char xlate_len, nr_slots;
wchar_t *unicode = NULL;
unsigned char work[8], bufname[260]; /* 256 + 4 */
int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
......@@ -159,7 +159,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
if (fat_get_entry(inode, &cpos, &bh, &de, &i_pos) == -1)
goto EODir;
parse_record:
long_slots = 0;
nr_slots = 0;
if (de->name[0] == DELETED_FLAG)
continue;
if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
......@@ -191,7 +191,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
slots = id & ~0x40;
if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
continue;
long_slots = slots;
nr_slots = slots;
alias_checksum = ds->alias_checksum;
slot = slots;
......@@ -228,7 +228,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
for (sum = 0, i = 0; i < 11; i++)
sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
if (sum != alias_checksum)
long_slots = 0;
nr_slots = 0;
}
memcpy(work, de->name, sizeof(de->name));
......@@ -276,7 +276,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
xlate_len)))
goto Found;
if (long_slots) {
if (nr_slots) {
xlate_len = utf8
?utf8_wcstombs(bufname, unicode, sizeof(bufname))
:uni16_to_x8(bufname, unicode, uni_xlate, nls_io);
......@@ -290,9 +290,10 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
}
Found:
nr_slots++; /* include the de */
sinfo->i_pos = i_pos;
sinfo->slot_off = cpos - (long_slots + 1) * sizeof(*de);
sinfo->nr_slots = long_slots;
sinfo->slot_off = cpos - nr_slots * sizeof(*de);
sinfo->nr_slots = nr_slots;
sinfo->de = de;
sinfo->bh = bh;
err = 0;
......@@ -759,6 +760,94 @@ int fat_scan(struct inode *dir, const unsigned char *name,
EXPORT_SYMBOL(fat_scan);
static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots)
{
struct super_block *sb = dir->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *de, *endp;
loff_t i_pos;
int err = 0, orig_slots;
while (nr_slots) {
bh = NULL;
if (fat_get_entry(dir, &pos, &bh, &de, &i_pos) < 0) {
err = -EIO;
break;
}
orig_slots = nr_slots;
endp = (struct msdos_dir_entry *)(bh->b_data + sb->s_blocksize);
while (nr_slots && de < endp) {
de->name[0] = DELETED_FLAG;
de++;
nr_slots--;
}
mark_buffer_dirty(bh);
if (IS_DIRSYNC(dir))
err = sync_dirty_buffer(bh);
brelse(bh);
if (err)
break;
/* pos is *next* de's position, so this does `- sizeof(de)' */
pos += ((orig_slots - nr_slots) * sizeof(*de)) - sizeof(*de);
}
return err;
}
int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo)
{
struct msdos_dir_entry *de;
struct buffer_head *bh;
int err = 0, nr_slots;
/*
* First stage: Remove the shortname. By this, the directory
* entry is removed.
*/
nr_slots = sinfo->nr_slots;
de = sinfo->de;
sinfo->de = NULL;
bh = sinfo->bh;
sinfo->bh = NULL;
while (nr_slots && de >= (struct msdos_dir_entry *)bh->b_data) {
de->name[0] = DELETED_FLAG;
de--;
nr_slots--;
}
mark_buffer_dirty(bh);
if (IS_DIRSYNC(dir))
err = sync_dirty_buffer(bh);
brelse(bh);
if (err)
return err;
dir->i_version++;
if (nr_slots) {
/*
* Second stage: remove the remaining longname slots.
* (This directory entry is already removed, and so return
* the success)
*/
err = __fat_remove_entries(dir, sinfo->slot_off, nr_slots);
if (err) {
printk(KERN_WARNING
"FAT: Couldn't remove the long name slots\n");
}
}
dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
if (IS_DIRSYNC(dir))
(void)fat_sync_inode(dir);
else
mark_inode_dirty(dir);
return 0;
}
EXPORT_SYMBOL(fat_remove_entries);
static struct buffer_head *fat_extend_dir(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
......
......@@ -721,7 +721,7 @@ static int vfat_add_entry(struct inode *dir, struct qstr *qname,
/* slots can't be less than 1 */
sinfo->slot_off = offset - sizeof(struct msdos_dir_slot) * slots;
sinfo->nr_slots = slots - 1;
sinfo->nr_slots = slots;
sinfo->de = de;
sinfo->bh = bh;
......@@ -817,39 +817,6 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, int mode,
return res;
}
static void vfat_remove_entry(struct inode *dir, struct fat_slot_info *sinfo)
{
struct super_block *sb = dir->i_sb;
struct msdos_dir_entry *de = sinfo->de;
struct buffer_head *bh = sinfo->bh;
loff_t offset, i_pos;
int i;
dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
dir->i_version++;
mark_inode_dirty(dir);
/* remove the shortname */
de->name[0] = DELETED_FLAG;
mark_buffer_dirty(bh);
if (sb->s_flags & MS_SYNCHRONOUS)
sync_dirty_buffer(bh);
/* remove the longname */
offset = sinfo->slot_off;
de = NULL;
for (i = sinfo->nr_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);
if (sb->s_flags & MS_SYNCHRONOUS)
sync_dirty_buffer(bh);
}
brelse(bh);
}
static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
......@@ -865,14 +832,15 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
if (err)
goto out;
err = fat_remove_entries(dir, &sinfo); /* and releases bh */
if (err)
goto out;
dir->i_nlink--;
inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
/* releases bh and syncs it if necessary */
vfat_remove_entry(dir, &sinfo);
dir->i_nlink--;
out:
unlock_kernel();
......@@ -891,12 +859,13 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry)
if (err)
goto out;
err = fat_remove_entries(dir, &sinfo); /* and releases bh */
if (err)
goto out;
inode->i_nlink = 0;
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
/* releases bh and syncs it if necessary */
vfat_remove_entry(dir, &sinfo);
out:
unlock_kernel();
......@@ -939,8 +908,7 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
mark_inode_dirty(inode);
/* releases bh ands syncs if necessary */
vfat_remove_entry(dir, &sinfo);
fat_remove_entries(dir, &sinfo); /* and releases bh */
iput(inode);
dir->i_nlink--;
goto out;
......@@ -956,49 +924,56 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
int err, is_dir;
struct fat_slot_info old_sinfo, sinfo;
old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
old_sinfo.bh = dotdot_bh = NULL;
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
lock_kernel();
err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);
if (err)
goto rename_done;
goto out;
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) {
err = -EIO;
goto rename_done;
goto out;
}
}
if (new_dentry->d_inode) {
err = vfat_find(new_dir, &new_dentry->d_name, &sinfo);
if (err || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
if (err)
goto out;
brelse(sinfo.bh);
if (MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
/* WTF??? Cry and fail. */
printk(KERN_WARNING "vfat_rename: fs corrupted\n");
goto rename_done;
goto out;
}
if (is_dir) {
err = fat_dir_empty(new_inode);
if (err)
goto rename_done;
goto out;
}
fat_detach(new_inode);
} else {
err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir,
&sinfo);
if (err)
goto rename_done;
goto out;
brelse(sinfo.bh);
}
new_dir->i_version++;
/* releases old_bh */
vfat_remove_entry(old_dir, &old_sinfo);
err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
old_sinfo.bh = NULL;
if (err)
goto out;
if (is_dir)
old_dir->i_nlink--;
fat_detach(old_inode);
fat_attach(old_inode, sinfo.i_pos);
mark_inode_dirty(old_inode);
......@@ -1019,7 +994,6 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_dir->i_sb->s_flags & MS_SYNCHRONOUS)
sync_dirty_buffer(dotdot_bh);
old_dir->i_nlink--;
if (new_inode) {
new_inode->i_nlink--;
} else {
......@@ -1027,10 +1001,9 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
mark_inode_dirty(new_dir);
}
}
rename_done:
out:
brelse(dotdot_bh);
brelse(old_sinfo.bh);
brelse(sinfo.bh);
unlock_kernel();
return err;
......
......@@ -333,6 +333,7 @@ extern int fat_subdirs(struct inode *dir);
extern int fat_scan(struct inode *dir, const unsigned char *name,
struct buffer_head **res_bh,
struct msdos_dir_entry **res_de, loff_t *i_pos);
extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo);
/* fat/fatent.c */
struct fat_entry {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment